001: /*
002: * $Id: GlyfSimple.java,v 1.2 2007/12/20 18:33:31 rbair Exp $
003: *
004: * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005: * Santa Clara, California 95054, U.S.A. All rights reserved.
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020: */
021:
022: package com.sun.pdfview.font.ttf;
023:
024: import java.nio.ByteBuffer;
025:
026: /**
027: * A single simple glyph in a pdf font.
028: */
029: public class GlyfSimple extends Glyf {
030: /** the end points of the various contours */
031: private short[] contourEndPts;
032:
033: /** the instructions */
034: private byte[] instructions;
035:
036: /** the flags */
037: private byte[] flags;
038:
039: /** the x coordinates */
040: private short[] xCoords;
041:
042: /** the y coordinates */
043: private short[] yCoords;
044:
045: /**
046: * Creates a new instance of a simple glyf
047: */
048: protected GlyfSimple() {
049: }
050:
051: /**
052: * Set the data for this glyf.
053: */
054: public void setData(ByteBuffer data) {
055: // int pos = data.position();
056: // byte[] prdata = new byte[data.remaining()];
057: // data.get(prdata);
058: // HexDump.printData(prdata);
059: // data.position(pos);
060:
061: // read the contour end points
062: short[] contourEndPts = new short[getNumContours()];
063: for (int i = 0; i < contourEndPts.length; i++) {
064: contourEndPts[i] = data.getShort();
065: }
066: setContourEndPoints(contourEndPts);
067:
068: // the number of points in the glyf is the number of the end
069: // point in the last contour
070: int numPoints = getContourEndPoint(getNumContours() - 1) + 1;
071:
072: // read the instructions
073: short numInstructions = data.getShort();
074: byte[] instructions = new byte[numInstructions];
075: for (int i = 0; i < instructions.length; i++) {
076: instructions[i] = data.get();
077: }
078: setInstructions(instructions);
079:
080: // read the flags
081: byte[] flags = new byte[numPoints];
082: for (int i = 0; i < flags.length; i++) {
083: flags[i] = data.get();
084:
085: // check for repeats
086: if ((flags[i] & 0x8) != 0) {
087: byte f = flags[i];
088: int n = (int) (data.get() & 0xff);
089: for (int c = 0; c < n; c++) {
090: flags[++i] = f;
091: }
092: }
093: }
094: setFlags(flags);
095:
096: // read the x coordinates
097: short[] xCoords = new short[numPoints];
098: for (int i = 0; i < xCoords.length; i++) {
099: if (i > 0) {
100: xCoords[i] = xCoords[i - 1];
101: }
102:
103: // read this value
104: if (xIsByte(i)) {
105: int val = (int) (data.get() & 0xff);
106: if (!xIsSame(i)) {
107: // the xIsSame bit controls the sign
108: val = -val;
109: }
110: xCoords[i] += val;
111: } else if (!xIsSame(i)) {
112: xCoords[i] += data.getShort();
113: }
114: }
115: setXCoords(xCoords);
116:
117: // read the y coordinates
118: short[] yCoords = new short[numPoints];
119: for (int i = 0; i < yCoords.length; i++) {
120: if (i > 0) {
121: yCoords[i] = yCoords[i - 1];
122: }
123: // read this value
124: if (yIsByte(i)) {
125: int val = (int) (data.get() & 0xff);
126: if (!yIsSame(i)) {
127: // the xIsSame bit controls the sign
128: val = -val;
129: }
130: yCoords[i] += val;
131: } else if (!yIsSame(i)) {
132: yCoords[i] += data.getShort();
133: }
134: }
135: setYCoords(yCoords);
136: }
137:
138: /**
139: * Get the data in this glyf as a byte buffer. Return the basic
140: * glyf data only, since there is no specific data. This method returns
141: * the data un-flipped, so subclasses can simply append to the allocated
142: * buffer.
143: */
144: public ByteBuffer getData() {
145: ByteBuffer buf = super .getData();
146:
147: // write the contour end points
148: for (int i = 0; i < getNumContours(); i++) {
149: buf.putShort(getContourEndPoint(i));
150: }
151:
152: // write the instructions
153: buf.putShort(getNumInstructions());
154: for (int i = 0; i < getNumInstructions(); i++) {
155: buf.put(getInstruction(i));
156: }
157:
158: // write the flags
159: for (int i = 0; i < getNumPoints(); i++) {
160: // check for repeats
161: byte r = 0;
162: while (i > 0 && (getFlag(i) == getFlag(i - 1))) {
163: r++;
164: i++;
165: }
166: if (r > 0) {
167: buf.put(r);
168: } else {
169: buf.put(getFlag(i));
170: }
171: }
172:
173: // write the x coordinates
174: for (int i = 0; i < getNumPoints(); i++) {
175: if (xIsByte(i)) {
176: buf.put((byte) getXCoord(i));
177: } else if (!xIsSame(i)) {
178: buf.putShort(getXCoord(i));
179: }
180: }
181:
182: // write the y coordinates
183: for (int i = 0; i < getNumPoints(); i++) {
184: if (yIsByte(i)) {
185: buf.put((byte) getYCoord(i));
186: } else if (!yIsSame(i)) {
187: buf.putShort(getYCoord(i));
188: }
189: }
190:
191: // don't flip the buffer, since it may be used by subclasses
192: return buf;
193: }
194:
195: /**
196: * Get the length of this glyf.
197: */
198: public short getLength() {
199: // start with the length of the superclass
200: short length = super .getLength();
201:
202: // add the length of the end points
203: length += getNumContours() * 2;
204:
205: // add the length of the instructions
206: length += 2 + getNumInstructions();
207:
208: // add the length of the flags, avoiding repeats
209: for (int i = 0; i < getNumPoints(); i++) {
210: // check for repeats
211: while (i > 0 && (getFlag(i) == getFlag(i - 1)))
212: ;
213: length++;
214: }
215:
216: // add the length of the xCoordinates
217: for (int i = 0; i < getNumPoints(); i++) {
218: if (xIsByte(i)) {
219: length++;
220: } else if (!xIsSame(i)) {
221: length += 2;
222: }
223:
224: if (yIsByte(i)) {
225: length++;
226: } else if (!yIsSame(i)) {
227: length += 2;
228: }
229: }
230:
231: return length;
232: }
233:
234: /**
235: * Get the end point of a given contour
236: */
237: public short getContourEndPoint(int index) {
238: return contourEndPts[index];
239: }
240:
241: /**
242: * Set the number of contours in this glyf
243: */
244: protected void setContourEndPoints(short[] contourEndPts) {
245: this .contourEndPts = contourEndPts;
246: }
247:
248: /**
249: * Get the number of instructions
250: */
251: public short getNumInstructions() {
252: return (short) instructions.length;
253: }
254:
255: /**
256: * Get a given instruction
257: */
258: public byte getInstruction(int index) {
259: return instructions[index];
260: }
261:
262: /**
263: * Set the instructions
264: */
265: protected void setInstructions(byte[] instructions) {
266: this .instructions = instructions;
267: }
268:
269: /**
270: * Get the number of points in the glyf
271: */
272: public short getNumPoints() {
273: return (short) flags.length;
274: }
275:
276: /**
277: * Get a given flag
278: */
279: public byte getFlag(int pointIndex) {
280: return flags[pointIndex];
281: }
282:
283: /**
284: * Determine whether the given point is on the curve
285: */
286: public boolean onCurve(int pointIndex) {
287: return ((getFlag(pointIndex) & 0x1) != 0);
288: }
289:
290: /**
291: * Determine whether the x value for the given point is byte or short.
292: * If true, it is a byte, if false it is a short
293: */
294: protected boolean xIsByte(int pointIndex) {
295: return ((getFlag(pointIndex) & 0x2) != 0);
296: }
297:
298: /**
299: * Determine whether the x value for the given point is byte or short.
300: * If true, it is a byte, if false it is a short
301: */
302: protected boolean yIsByte(int pointIndex) {
303: return ((getFlag(pointIndex) & 0x4) != 0);
304: }
305:
306: /**
307: * Determine whether this flag repeats
308: */
309: protected boolean repeat(int pointIndex) {
310: return ((getFlag(pointIndex) & 0x8) != 0);
311: }
312:
313: /**
314: * Determine whether the x value for the given point is the same as
315: * the previous value.
316: */
317: protected boolean xIsSame(int pointIndex) {
318: return ((getFlag(pointIndex) & 0x10) != 0);
319: }
320:
321: /**
322: * Determine whether the y value for the given point is the same as
323: * the previous value.
324: */
325: protected boolean yIsSame(int pointIndex) {
326: return ((getFlag(pointIndex) & 0x20) != 0);
327: }
328:
329: /**
330: * Set the flags
331: */
332: protected void setFlags(byte[] flags) {
333: this .flags = flags;
334: }
335:
336: /**
337: * Get a given x coordinate
338: */
339: public short getXCoord(int pointIndex) {
340: return xCoords[pointIndex];
341: }
342:
343: /**
344: * Set the x coordinates
345: */
346: protected void setXCoords(short[] xCoords) {
347: this .xCoords = xCoords;
348: }
349:
350: /**
351: * Get a given y coordinate
352: */
353: public short getYCoord(int pointIndex) {
354: return yCoords[pointIndex];
355: }
356:
357: /**
358: * Set the x coordinates
359: */
360: protected void setYCoords(short[] yCoords) {
361: this.yCoords = yCoords;
362: }
363: }
|