--- /dev/null
+/*
+ * Copyright (c) 2009, Takeyuki Nagao
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+package jp.sourceforge.dvibrowser.dvicore.font;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+
+import jp.sourceforge.dvibrowser.dvicore.DviConstants;
+import jp.sourceforge.dvibrowser.dvicore.DviException;
+import jp.sourceforge.dvibrowser.dvicore.DviFontSpec;
+import jp.sourceforge.dvibrowser.dvicore.DviObject;
+import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport;
+import jp.sourceforge.dvibrowser.dvicore.api.DviInput;
+import jp.sourceforge.dvibrowser.dvicore.api.FullMetrics;
+import jp.sourceforge.dvibrowser.dvicore.io.DviInputStreamReader;
+import jp.sourceforge.dvibrowser.dvicore.util.DviUtils;
+
+
+// TODO: support Tategumi
+
+public class TexFontMetrics
+extends DviObject
+implements FullMetrics
+{
+ private static final long serialVersionUID = 962603909880917980L;
+
+ // TODO: outsource JFM configuration
+ private boolean enableJFM = true;
+
+ private boolean isJFM; // For Japanese pTeX
+
+private int checkSum;
+ private int designSize;
+
+ private final String name;
+
+ private final HashMap<Integer, Record> ct2rec
+ = new HashMap<Integer, Record>();
+ private HashMap<Integer, Integer> code2ct;
+
+ public TexFontMetrics(DviContextSupport dcs, File file)
+ throws DviException
+ {
+ super(dcs);
+ FileInputStream is = null;
+ try {
+ is = new FileInputStream(file);
+ parseInputStream(is);
+ } catch (IOException ex) {
+ DviUtils.silentClose(is);
+ throw new DviException(ex);
+ }
+ name = getClass().getName()
+ + "--" + file.getPath()
+ + "--" + file.lastModified()
+ ;
+ }
+
+ public TexFontMetrics(DviContextSupport dcs, InputStream is)
+ throws DviException
+ {
+ super(dcs);
+ try {
+ parseInputStream(is);
+ } catch (IOException ex) {
+ throw new DviException(ex);
+ }
+ name = getClass().getName()
+ + "--" + is
+ + "--" + System.currentTimeMillis()
+ ;
+ }
+
+ @SuppressWarnings("unused")
+ protected void parseInputStream(InputStream is)
+ throws IOException, DviException
+ {
+ DviInputStreamReader in = new DviInputStreamReader(
+ new BufferedInputStream(is, 1024)
+ );
+
+ long start = in.getOffset();
+
+ int id; // For Japanese pTeX
+ int nt; // For Japanese pTeX
+ int lf;
+ int lh;
+ int bc;
+ int ec;
+ int nw;
+ int nh;
+ int nd;
+ int ni;
+ int nl;
+ int nk;
+ int ne;
+ int np;
+
+ int numChars;
+
+ if (enableJFM) {
+ id = in.readU2();
+ nt = in.readU2();
+ isJFM = (id == DviConstants.TFM_ID_TATEGUMI || id == DviConstants.TFM_ID_YOKOGUMI);
+ if (isJFM) {
+ lf = in.readU2();
+ lh = in.readU2();
+ } else {
+ lf = id;
+ lh = nt;
+ id = 0;
+ nt = 0;
+ }
+ } else {
+ id = 0;
+ nt = 0;
+ lf = in.readU2();
+ lh = in.readU2();
+ isJFM = false;
+ }
+
+ bc = in.readU2();
+ ec = in.readU2();
+ nw = in.readU2();
+ nh = in.readU2();
+ nd = in.readU2();
+ ni = in.readU2();
+ nl = in.readU2();
+ nk = in.readU2();
+ ne = in.readU2();
+ np = in.readU2();
+ numChars = ec - bc + 1;
+
+ // header
+ int [] header_t = readBuffer(in, lh);
+ {
+ checkSum = header_t[0];
+ designSize = header_t[1];
+ }
+
+ // character type map (for Japanese JFM)
+ if (isJFM) {
+ code2ct = new HashMap<Integer, Integer>();
+ for (int i=0; i<nt; i++) {
+ final int from = in.readU2();
+ final int to = in.readU2();
+ code2ct.put(from, to);
+ }
+ } else {
+ code2ct = null;
+ }
+
+ int [] char_info_t = readBuffer(in, numChars);
+ int [] width_t = readBuffer(in, nw);
+ int [] height_t = readBuffer(in, nh);
+ int [] depth_t = readBuffer(in, nd);
+ int [] italic_t = readBuffer(in, ni);
+ int [] lig_kern_t = readBuffer(in, nl);
+ int [] kern_t = readBuffer(in, nk);
+ int [] exten_t = readBuffer(in, ne);
+ int [] param_t = readBuffer(in, np);
+
+ long size = in.getOffset() - start;
+ if (lf * 4 != size ||
+ lf != (isJFM ? 7 : 6) +
+ lh +
+ nt +
+ numChars +
+ nw +
+ nh +
+ nd +
+ ni +
+ nl +
+ nk +
+ ne +
+ np)
+ throw new DviException
+ ("Length mismatch in TFM data");
+
+ if (isJFM && bc != 0)
+ throw new DviException
+ ("bc must be 0 in JFM data.");
+
+ for (int i=0; i<numChars; i++) {
+ final int ct = i + bc;
+ final int ci = char_info_t[i];
+ final int wi = (ci >>> 24) & 0xff;
+ final int hi = (ci >>> 20) & 0x0f;
+ final int di = (ci >>> 16) & 0x0f;
+ final int ii = (ci >>> 10) & 0x3f;
+ final int tag = (ci >>> 8) & 0x03;
+ final int rem = (ci >>> 0) & 0xff;
+
+ final int width = width_t [wi];
+ final int height = height_t[hi];
+ final int depth = depth_t [di];
+ final int italic = italic_t[ii];
+
+ ct2rec.put(ct, new Record(width, height, depth, italic));
+ }
+ }
+
+ private static int [] readBuffer(DviInput in, int length)
+ throws IOException
+ {
+ int [] buf = new int[length];
+ for (int i=0; i<length; i++)
+ buf[i] = in.readU4();
+ return buf;
+ }
+
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public int getCheckSum() {
+ return checkSum;
+ }
+
+ public int getDesignSize() {
+ return designSize;
+ }
+
+ public boolean isJFM() {
+ return isJFM;
+ }
+
+ public boolean hasChar(int code)
+ {
+ return isJFM ? true : ct2rec.containsKey(code);
+ }
+
+ private int codeToCt(int code)
+ {
+ return (code2ct == null) ? code :
+ code2ct.containsKey(code) ? code2ct.get(code) : 0;
+ }
+ private Record getRecord(int code)
+ {
+ return ct2rec.get(codeToCt(code));
+ }
+
+ public int getTfmWidth(int code)
+ {
+ Record rec = getRecord(code);
+ return (rec != null) ? rec.width : 0;
+ }
+ public int getTfmHeight(int code)
+ {
+ Record rec = getRecord(code);
+ return (rec != null) ? rec.height : 0;
+ }
+ public int getTfmDepth(int code)
+ {
+ Record rec = getRecord(code);
+ return (rec != null) ? rec.depth : 0;
+ }
+ public int getTfmItalic(int code)
+ {
+ Record rec = getRecord(code);
+ return (rec != null) ? rec.italic : 0;
+ }
+
+ public static String getTfmFilename(DviFontSpec spec)
+ {
+ String tfm = spec.name() + ".tfm";
+ return tfm;
+ }
+
+ private static class Record implements java.io.Serializable {
+ private static final long serialVersionUID = 1638947545775532119L;
+ private final int width;
+ private final int height;
+ private final int depth;
+ private final int italic;
+
+ private Record(int width, int height, int depth, int italic) {
+ this.width = width;
+ this.height = height;
+ this.depth = depth;
+ this.italic = italic;
+ }
+ }
+}