com.sun.pdfview.font.ttf.GlyfSimple Maven / Gradle / Ivy
/*
* $Id: GlyfSimple.java,v 1.2 2007/12/20 18:33:31 rbair 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;
/**
* A single simple glyph in a pdf font.
*/
public class GlyfSimple extends Glyf {
/** the end points of the various contours */
private short[] contourEndPts;
/** the instructions */
private byte[] instructions;
/** the flags */
private byte[] flags;
/** the x coordinates */
private short[] xCoords;
/** the y coordinates */
private short[] yCoords;
/**
* Creates a new instance of a simple glyf
*/
protected GlyfSimple() {
}
/**
* Set the data for this glyf.
*/
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
short[] contourEndPts = new short[getNumContours()];
for (int i = 0; i < contourEndPts.length; i++) {
contourEndPts[i] = data.getShort();
}
setContourEndPoints(contourEndPts);
// the number of points in the glyf is the number of the end
// point in the last contour
int numPoints = getContourEndPoint(getNumContours() - 1) + 1;
// read the instructions
short numInstructions = data.getShort();
byte[] instructions = new byte[numInstructions];
for (int i = 0; i < instructions.length; i++) {
instructions[i] = data.get();
}
setInstructions(instructions);
// read the flags
byte[] flags = new byte[numPoints];
for (int i = 0; i < flags.length; i++) {
flags[i] = data.get();
// check for repeats
if ((flags[i] & 0x8) != 0) {
byte f = flags[i];
int n = (int) (data.get() & 0xff);
for (int c = 0; c < n; c++) {
flags[++i] = f;
}
}
}
setFlags(flags);
// read the x coordinates
short[] xCoords = new short[numPoints];
for (int i = 0; i < xCoords.length; i++) {
if (i > 0) {
xCoords[i] = xCoords[i - 1];
}
// read this value
if (xIsByte(i)) {
int val = (int) (data.get() & 0xff);
if (!xIsSame(i)) {
// the xIsSame bit controls the sign
val = -val;
}
xCoords[i] += val;
} else if (!xIsSame(i)) {
xCoords[i] += data.getShort();
}
}
setXCoords(xCoords);
// read the y coordinates
short[] yCoords = new short[numPoints];
for (int i = 0; i < yCoords.length; i++) {
if (i > 0) {
yCoords[i] = yCoords[i - 1];
}
// read this value
if (yIsByte(i)) {
int val = (int) (data.get() & 0xff);
if (!yIsSame(i)) {
// the xIsSame bit controls the sign
val = -val;
}
yCoords[i] += val;
} else if (!yIsSame(i)) {
yCoords[i] += data.getShort();
}
}
setYCoords(yCoords);
}
/**
* Get the data in this glyf as a byte buffer. Return the basic
* glyf data only, since there is no specific data. This method returns
* the data un-flipped, so subclasses can simply append to the allocated
* buffer.
*/
public ByteBuffer getData() {
ByteBuffer buf = super.getData();
// write the contour end points
for (int i = 0; i < getNumContours(); i++) {
buf.putShort(getContourEndPoint(i));
}
// write the instructions
buf.putShort(getNumInstructions());
for (int i = 0; i < getNumInstructions(); i++) {
buf.put(getInstruction(i));
}
// write the flags
for (int i = 0; i < getNumPoints(); i++) {
// check for repeats
byte r = 0;
while (i > 0 && (getFlag(i) == getFlag(i - 1))) {
r++;
i++;
}
if (r > 0) {
buf.put(r);
} else {
buf.put(getFlag(i));
}
}
// write the x coordinates
for (int i = 0; i < getNumPoints(); i++) {
if (xIsByte(i)) {
buf.put((byte) getXCoord(i));
} else if (!xIsSame(i)) {
buf.putShort(getXCoord(i));
}
}
// write the y coordinates
for (int i = 0; i < getNumPoints(); i++) {
if (yIsByte(i)) {
buf.put((byte) getYCoord(i));
} else if (!yIsSame(i)) {
buf.putShort(getYCoord(i));
}
}
// don't flip the buffer, since it may be used by subclasses
return buf;
}
/**
* Get the length of this glyf.
*/
public short getLength() {
// start with the length of the superclass
short length = super.getLength();
// add the length of the end points
length += getNumContours() * 2;
// add the length of the instructions
length += 2 + getNumInstructions();
// add the length of the flags, avoiding repeats
for (int i = 0; i < getNumPoints(); i++) {
// check for repeats
while (i > 0 && (getFlag(i) == getFlag(i - 1)));
length++;
}
// add the length of the xCoordinates
for (int i = 0; i < getNumPoints(); i++) {
if (xIsByte(i)) {
length++;
} else if (!xIsSame(i)) {
length += 2;
}
if (yIsByte(i)) {
length++;
} else if (!yIsSame(i)) {
length += 2;
}
}
return length;
}
/**
* Get the end point of a given contour
*/
public short getContourEndPoint(int index) {
return contourEndPts[index];
}
/**
* Set the number of contours in this glyf
*/
protected void setContourEndPoints(short[] contourEndPts) {
this.contourEndPts = contourEndPts;
}
/**
* 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;
}
/**
* Get the number of points in the glyf
*/
public short getNumPoints() {
return (short) flags.length;
}
/**
* Get a given flag
*/
public byte getFlag(int pointIndex) {
return flags[pointIndex];
}
/**
* Determine whether the given point is on the curve
*/
public boolean onCurve(int pointIndex) {
return ((getFlag(pointIndex) & 0x1) != 0);
}
/**
* Determine whether the x value for the given point is byte or short.
* If true, it is a byte, if false it is a short
*/
protected boolean xIsByte(int pointIndex) {
return ((getFlag(pointIndex) & 0x2) != 0);
}
/**
* Determine whether the x value for the given point is byte or short.
* If true, it is a byte, if false it is a short
*/
protected boolean yIsByte(int pointIndex) {
return ((getFlag(pointIndex) & 0x4) != 0);
}
/**
* Determine whether this flag repeats
*/
protected boolean repeat(int pointIndex) {
return ((getFlag(pointIndex) & 0x8) != 0);
}
/**
* Determine whether the x value for the given point is the same as
* the previous value.
*/
protected boolean xIsSame(int pointIndex) {
return ((getFlag(pointIndex) & 0x10) != 0);
}
/**
* Determine whether the y value for the given point is the same as
* the previous value.
*/
protected boolean yIsSame(int pointIndex) {
return ((getFlag(pointIndex) & 0x20) != 0);
}
/**
* Set the flags
*/
protected void setFlags(byte[] flags) {
this.flags = flags;
}
/**
* Get a given x coordinate
*/
public short getXCoord(int pointIndex) {
return xCoords[pointIndex];
}
/**
* Set the x coordinates
*/
protected void setXCoords(short[] xCoords) {
this.xCoords = xCoords;
}
/**
* Get a given y coordinate
*/
public short getYCoord(int pointIndex) {
return yCoords[pointIndex];
}
/**
* Set the x coordinates
*/
protected void setYCoords(short[] yCoords) {
this.yCoords = yCoords;
}
}