OSDN Git Service

Change directory structure.
[dvibrowser/dvi2epub.git] / src / main / java / jp / sourceforge / dvibrowser / dvicore / font / TexFontMetrics.java
diff --git a/src/main/java/jp/sourceforge/dvibrowser/dvicore/font/TexFontMetrics.java b/src/main/java/jp/sourceforge/dvibrowser/dvicore/font/TexFontMetrics.java
new file mode 100644 (file)
index 0000000..3b8c334
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * 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;
+    }
+  }
+}