jdk/src/share/classes/sun/font/FileFont.java
changeset 2 90ce3da70b43
child 2606 09ad5edb5330
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/font/FileFont.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code 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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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 in the LICENSE file that
+ * accompanied this code).
+ *
+ * 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 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.font;
+
+import java.lang.ref.Reference;
+import java.awt.FontFormatException;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import sun.java2d.Disposer;
+import sun.java2d.DisposerRecord;
+
+import java.lang.ref.WeakReference;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteOrder;
+import java.nio.MappedByteBuffer;
+import java.nio.BufferUnderflowException;
+import java.nio.channels.ClosedChannelException;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.awt.Font;
+
+public abstract class FileFont extends PhysicalFont {
+
+    protected boolean useJavaRasterizer = true;
+
+    /* I/O and file operations are always synchronized on the font
+     * object. Two threads can be accessing the font and retrieving
+     * information, and synchronized only to the extent that filesystem
+     * operations require.
+     * A limited number of files can be open at a time, to limit the
+     * absorption of file descriptors. If a file needs to be opened
+     * when there are none free, then the synchronization of all I/O
+     * ensures that any in progress operation will complete before some
+     * other thread closes the descriptor in order to allocate another one.
+     */
+    // NB consider using a RAF. FIS has finalize method so may take a
+    // little longer to be GC'd. We don't use this stream at all anyway.
+    // In fact why increase the size of a FileFont object if the stream
+    // isn't needed ..
+    //protected FileInputStream stream;
+    //protected FileChannel channel;
+    protected int fileSize;
+
+    protected FontScaler scaler;
+
+    /* The following variables are used, (and in the case of the arrays,
+     * only initialised) for select fonts where a native scaler may be
+     * used to get glyph images and metrics.
+     * glyphToCharMap is filled in on the fly and used to do a reverse
+     * lookup when a FileFont needs to get the charcode back from a glyph
+     * code so it can re-map via a NativeGlyphMapper to get a native glyph.
+     * This isn't a big hit in time, since a boolean test is sufficient
+     * to choose the usual default path, nor in memory for fonts which take
+     * the native path, since fonts have contiguous zero-based glyph indexes,
+     * and these obviously do all exist in the font.
+     */
+    protected boolean checkedNatives;
+    protected boolean useNatives;
+    protected NativeFont[] nativeFonts;
+    protected char[] glyphToCharMap;
+    /*
+     * @throws FontFormatException - if the font can't be opened
+     */
+    FileFont(String platname, Object nativeNames)
+        throws FontFormatException {
+
+        super(platname, nativeNames);
+    }
+
+    FontStrike createStrike(FontStrikeDesc desc) {
+        if (!checkedNatives) {
+           checkUseNatives();
+        }
+        return new FileFontStrike(this, desc);
+    }
+
+    protected boolean checkUseNatives() {
+        checkedNatives = true;
+        return useNatives;
+    }
+
+    /* This method needs to be accessible to FontManager if there is
+     * file pool management. It may be a no-op.
+     */
+    protected abstract void close();
+
+
+    /*
+     * This is the public interface. The subclasses need to implement
+     * this. The returned block may be longer than the requested length.
+     */
+    abstract ByteBuffer readBlock(int offset, int length);
+
+    public boolean canDoStyle(int style) {
+        return true;
+    }
+
+    void setFileToRemove(File file) {
+        Disposer.addObjectRecord(this,
+                                 new CreatedFontFileDisposerRecord(file));
+    }
+
+    /* This is called when a font scaler is determined to
+     * be unusable (ie bad).
+     * We want to replace current scaler with NullFontScaler, so
+     * we never try to use same font scaler again.
+     * Scaler native resources could have already been disposed
+     * or they will be eventually by Java2D disposer.
+     * However, it should be safe to call dispose() explicitly here.
+     *
+     * For safety we also invalidate all strike's scaler context.
+     * So, in case they cache pointer to native scaler
+     * it will not ever be used.
+     *
+     * It also appears desirable to remove all the entries from the
+     * cache so no other code will pick them up. But we can't just
+     * 'delete' them as code may be using them. And simply dropping
+     * the reference to the cache will make the reference objects
+     * unreachable and so they will not get disposed.
+     * Since a strike may hold (via java arrays) native pointers to many
+     * rasterised glyphs, this would be a memory leak.
+     * The solution is :
+     * - to move all the entries to another map where they
+     *   are no longer locatable
+     * - update FontStrikeDisposer to be able to distinguish which
+     * map they are held in via a boolean flag
+     * Since this isn't expected to be anything other than an extremely
+     * rare maybe it is not worth doing this last part.
+     */
+    synchronized void deregisterFontAndClearStrikeCache() {
+        FontManager.deRegisterBadFont(this);
+
+        for (Reference strikeRef : strikeCache.values()) {
+            if (strikeRef != null) {
+                /* NB we know these are all FileFontStrike instances
+                 * because the cache is on this FileFont
+                 */
+                FileFontStrike strike = (FileFontStrike)strikeRef.get();
+                if (strike != null && strike.pScalerContext != 0L) {
+                    scaler.invalidateScalerContext(strike.pScalerContext);
+                }
+            }
+        }
+        scaler.dispose();
+        scaler = FontManager.getNullScaler();
+    }
+
+    StrikeMetrics getFontMetrics(long pScalerContext) {
+        try {
+            return getScaler().getFontMetrics(pScalerContext);
+        } catch (FontScalerException fe) {
+            scaler = FontManager.getNullScaler();
+            return getFontMetrics(pScalerContext);
+        }
+    }
+
+    float getGlyphAdvance(long pScalerContext, int glyphCode) {
+        try {
+            return getScaler().getGlyphAdvance(pScalerContext, glyphCode);
+        } catch (FontScalerException fe) {
+            scaler = FontManager.getNullScaler();
+            return getGlyphAdvance(pScalerContext, glyphCode);
+        }
+    }
+
+    void getGlyphMetrics(long pScalerContext, int glyphCode, Point2D.Float metrics) {
+        try {
+            getScaler().getGlyphMetrics(pScalerContext, glyphCode, metrics);
+        } catch (FontScalerException fe) {
+            scaler = FontManager.getNullScaler();
+            getGlyphMetrics(pScalerContext, glyphCode, metrics);
+        }
+    }
+
+    long getGlyphImage(long pScalerContext, int glyphCode) {
+        try {
+            return getScaler().getGlyphImage(pScalerContext, glyphCode);
+        } catch (FontScalerException fe) {
+            scaler = FontManager.getNullScaler();
+            return getGlyphImage(pScalerContext, glyphCode);
+        }
+    }
+
+    Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext, int glyphCode) {
+        try {
+            return getScaler().getGlyphOutlineBounds(pScalerContext, glyphCode);
+        } catch (FontScalerException fe) {
+            scaler = FontManager.getNullScaler();
+            return getGlyphOutlineBounds(pScalerContext, glyphCode);
+        }
+    }
+
+    GeneralPath getGlyphOutline(long pScalerContext, int glyphCode, float x, float y) {
+        try {
+            return getScaler().getGlyphOutline(pScalerContext, glyphCode, x, y);
+        } catch (FontScalerException fe) {
+            scaler = FontManager.getNullScaler();
+            return getGlyphOutline(pScalerContext, glyphCode, x, y);
+        }
+    }
+
+    GeneralPath getGlyphVectorOutline(long pScalerContext, int[] glyphs, int numGlyphs, float x, float y) {
+        try {
+            return getScaler().getGlyphVectorOutline(pScalerContext, glyphs, numGlyphs, x, y);
+        } catch (FontScalerException fe) {
+            scaler = FontManager.getNullScaler();
+            return getGlyphVectorOutline(pScalerContext, glyphs, numGlyphs, x, y);
+        }
+    }
+
+    /* T1 & TT implementation differ so this method is abstract.
+       NB: null should not be returned here! */
+    protected abstract FontScaler getScaler();
+
+    protected long getUnitsPerEm() {
+        return getScaler().getUnitsPerEm();
+    }
+
+    private static class CreatedFontFileDisposerRecord implements DisposerRecord {
+
+        File fontFile = null;
+
+        private CreatedFontFileDisposerRecord(File file) {
+            fontFile = file;
+        }
+
+        public void dispose() {
+            java.security.AccessController.doPrivileged(
+                 new java.security.PrivilegedAction() {
+                      public Object run() {
+                          if (fontFile != null) {
+                              try {
+                                  /* REMIND: is it possible that the file is
+                                   * still open? It will be closed when the
+                                   * font2D is disposed but could this code
+                                   * execute first? If so the file would not
+                                   * be deleted on MS-windows.
+                                   */
+                                  fontFile.delete();
+                                  /* remove from delete on exit hook list : */
+                                  FontManager.tmpFontFiles.remove(fontFile);
+                              } catch (Exception e) {
+                              }
+                          }
+                          return null;
+                      }
+            });
+        }
+    }
+}