/* * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program 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 * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package com.sun.pisces; import java.io.DataInputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.util.Hashtable; class Face { PathStore[] paths = new PathStore[256]; int[] minX = new int[256]; int[] minY = new int[256]; int[] width = new int[256]; int[] height = new int[256]; double scale; public Face(InputStream in) throws IOException { GZIPInputStream gin = new GZIPInputStream(in); DataInputStream dis = new DataInputStream(gin); String name = dis.readUTF(); String style = dis.readUTF(); this.scale = 65536.0/dis.readDouble(); while (true) { char glyph; try { glyph = dis.readChar(); } catch (EOFException eof) { return; } int gx = dis.readInt(); int gy = dis.readInt(); int gwidth = dis.readInt(); int gheight = dis.readInt(); int numEntries = dis.readInt(); PathStore ps = new PathStore(numEntries); int[] x = new int[4]; int[] y = new int[4]; int sx0 = 0, sy0 = 0, xp = 0, yp = 0; boolean prevIsQuad = false; boolean prevIsCubic = false; while (true) { char tok = dis.readChar(); if (tok == 'Z') { ps.close(); ps.end(); break; } else if (tok == 'E') { ps.end(); break; } int x0 = x[0]; int y0 = y[0]; switch (tok) { case 'M': // readInts(x, 1); // readInts(y, 1); x[0] = dis.readInt(); y[0] = dis.readInt(); break; case 'm': // readShorts(x, 1); // readShorts(y, 1); x[0] += dis.readShort(); y[0] += dis.readShort(); break; case 'n': // readBytes(x, 1); // readBytes(y, 1); x[0] += dis.readByte(); y[0] += dis.readByte(); break; case 'H': // readInts(x, 1); x[0] = dis.readInt(); break; case 'h': // readShorts(x, 1); x[0] += dis.readShort(); break; case 'i': // readBytes(x, 1); x[0] += dis.readByte(); break; case 'V': // readInts(y, 1); y[0] = dis.readInt(); break; case 'v': // readShorts(y, 1); y[0] += dis.readShort(); break; case 'w': // readBytes(y, 1); y[0] += dis.readByte(); break; case 'L': // readInts(x, 1); // readInts(y, 1); x[0] = dis.readInt(); y[0] = dis.readInt(); break; case 'l': // readShorts(x, 1); // readShorts(y, 1); x[0] += dis.readShort(); y[0] += dis.readShort(); break; case 'k': // readBytes(x, 1); // readBytes(y, 1); x[0] += dis.readByte(); y[0] += dis.readByte(); break; case 'Q': // readInts(x, 2); // readInts(y, 2); x[0] = dis.readInt(); y[0] = dis.readInt(); x[1] = dis.readInt(); y[1] = dis.readInt(); break; case 'q': // readShorts(x, 2); // readShorts(y, 2); x[0] = x0 + dis.readShort(); y[0] = y0 + dis.readShort(); x[1] = x0 + dis.readShort(); y[1] = y0 + dis.readShort(); break; case 'r': // readBytes(x, 2); // readBytes(y, 2); x[0] = x0 + dis.readByte(); y[0] = y0 + dis.readByte(); x[1] = x0 + dis.readByte(); y[1] = y0 + dis.readByte(); break; case 'T': x[0] = x0 + (prevIsQuad ? (x0 - xp) : 0); y[0] = y0 + (prevIsQuad ? (y0 - yp) : 0); x[1] = dis.readInt(); y[1] = dis.readInt(); break; case 't': x[0] = x0 + (prevIsQuad ? (x0 - xp) : 0); y[0] = y0 + (prevIsQuad ? (y0 - yp) : 0); x[1] = x0 + dis.readShort(); y[1] = y0 + dis.readShort(); break; case 'u': x[0] = x0 + (prevIsQuad ? (x0 - xp) : 0); y[0] = y0 + (prevIsQuad ? (y0 - yp) : 0); x[1] = x0 + dis.readByte(); y[1] = y0 + dis.readByte(); break; case 'C': // readInts(x, 3); // readInts(y, 3); x[0] = dis.readInt(); y[0] = dis.readInt(); x[1] = dis.readInt(); y[1] = dis.readInt(); x[2] = dis.readInt(); y[2] = dis.readInt(); break; case 'c': x[0] = x0 + dis.readShort(); y[0] = y0 + dis.readShort(); x[1] = x0 + dis.readShort(); y[1] = y0 + dis.readShort(); x[2] = x0 + dis.readShort(); y[2] = y0 + dis.readShort(); break; case 'd': x[0] = x0 + dis.readByte(); y[0] = y0 + dis.readByte(); x[1] = x0 + dis.readByte(); y[1] = y0 + dis.readByte(); x[2] = x0 + dis.readByte(); y[2] = y0 + dis.readByte(); break; case 'S': x[0] = x0 + (prevIsCubic ? (x0 - xp) : 0); y[0] = y0 + (prevIsCubic ? (y0 - yp) : 0); x[1] = dis.readInt(); y[1] = dis.readInt(); x[2] = dis.readInt(); y[2] = dis.readInt(); break; case 's': x[0] = x0 + (prevIsCubic ? (x0 - xp) : 0); y[0] = y0 + (prevIsCubic ? (y0 - yp) : 0); x[1] = x0 + dis.readShort(); y[1] = y0 + dis.readShort(); x[2] = x0 + dis.readShort(); y[2] = y0 + dis.readShort(); break; case 'p': x[0] = x0 + (prevIsCubic ? (x0 - xp) : 0); y[0] = y0 + (prevIsCubic ? (y0 - yp) : 0); x[1] = x0 + dis.readByte(); y[1] = y0 + dis.readByte(); x[2] = x0 + dis.readByte(); y[2] = y0 + dis.readByte(); break; } switch (tok) { case 'M': case 'm': case 'n': ps.moveTo(x[0], y[0]); sx0 = x[0]; sy0 = y[0]; prevIsQuad = prevIsCubic = false; break; case 'H': case 'h': case 'i': case 'V': case 'v': case 'w': case 'L': case 'l': case 'k': ps.lineTo(x[0], y[0]); prevIsQuad = prevIsCubic = false; break; case 'Q': case 'q': case 'r': case 'T': case 't': case 'u': ps.quadTo(x[0], y[0], x[1], y[1]); xp = x[0]; yp = y[0]; x[0] = x[1]; y[0] = y[1]; prevIsQuad = true; prevIsCubic = false; break; case 'C': case 'c': case 'd': case 'S': case 's': case 'p': ps.cubicTo(x[0], y[0], x[1], y[1], x[2], y[2]); xp = x[1]; yp = y[1]; x[0] = x[2]; y[0] = y[2]; prevIsQuad = false; prevIsCubic = true; break; case 'z': ps.close(); x[0] = sx0; y[0] = sy0; prevIsQuad = prevIsCubic = false; break; } } int idx = glyph; paths[idx] = ps; minX[idx] = gx; minY[idx] = gy; width[idx] = gwidth; height[idx] = gheight; } } } public class PiscesFont { public static final int PLAIN = 0; public static final int BOLD = 1; public static final int ITALIC = 2; private static final String[] styles = { "PLAIN", "BOLD", "ITALIC", "BOLD+ITALIC" }; private static Hashtable faces = new Hashtable(); String name; int style; int size; Face face; // size is S15.16 public PiscesFont(String name, int style, int size) throws IOException { this.face = getFace(name, style); this.name = name; this.style = style; this.size = size; } private static Face getFace(String name, int style) throws IOException { String fname = "/" + name + "_" + styles[style] + ".fnt.gz"; Face face = (Face)faces.get(fname); if (face == null) { InputStream in = (PiscesFont.class).getResourceAsStream(fname); if (in == null && style != PLAIN) { return getFace(name, PLAIN); } face = new Face(in); faces.put(fname, face); } return face; } public String getName() { return name; } public int getStyle() { return style; } public int getSize() { return size; } public void getBounds(String s, int[] bounds) { // int size = (int)(this.size*face.scale); int c = (int)s.charAt(0); int minX = face.minX[c]; int minY = face.minY[c]; int width = 0; int height = 0; for (int i = 0; i < s.length(); i++) { c = (int)s.charAt(i); width += (int)((long)face.width[c]*size >> 16); if (height < face.height[c]) { height = face.height[c]; } } bounds[0] = minX; bounds[1] = minY; bounds[2] = width; bounds[3] = height; } public void produce(PathSink consumer, String s, int x, int y) { int size2 = (int)(this.size*face.scale); for (int i = 0; i < s.length(); i++) { int c = (int)s.charAt(i); PathStore glyph = face.paths[c]; int width = (int)((long)face.width[c]*size >> 16); Transform6 transform = new Transform6(size2, 0, 0, size2, x, y); Transformer pt = new Transformer(consumer, transform); glyph.produce(pt); x += width; } } }