0N/A/*
3909N/A * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.font;
0N/A
0N/Aimport java.lang.ref.Reference;
0N/Aimport java.awt.FontFormatException;
0N/Aimport java.awt.geom.GeneralPath;
0N/Aimport java.awt.geom.Point2D;
0N/Aimport java.awt.geom.Rectangle2D;
0N/Aimport java.io.File;
0N/Aimport java.nio.ByteBuffer;
0N/Aimport sun.java2d.Disposer;
0N/Aimport sun.java2d.DisposerRecord;
0N/A
0N/Aimport java.io.IOException;
3784N/Aimport java.security.AccessController;
3784N/Aimport java.security.PrivilegedActionException;
3784N/Aimport java.security.PrivilegedExceptionAction;
0N/A
0N/Apublic abstract class FileFont extends PhysicalFont {
0N/A
0N/A protected boolean useJavaRasterizer = true;
0N/A
0N/A /* I/O and file operations are always synchronized on the font
0N/A * object. Two threads can be accessing the font and retrieving
0N/A * information, and synchronized only to the extent that filesystem
0N/A * operations require.
0N/A * A limited number of files can be open at a time, to limit the
0N/A * absorption of file descriptors. If a file needs to be opened
0N/A * when there are none free, then the synchronization of all I/O
0N/A * ensures that any in progress operation will complete before some
0N/A * other thread closes the descriptor in order to allocate another one.
0N/A */
0N/A // NB consider using a RAF. FIS has finalize method so may take a
0N/A // little longer to be GC'd. We don't use this stream at all anyway.
0N/A // In fact why increase the size of a FileFont object if the stream
0N/A // isn't needed ..
0N/A //protected FileInputStream stream;
0N/A //protected FileChannel channel;
0N/A protected int fileSize;
0N/A
0N/A protected FontScaler scaler;
0N/A
0N/A /* The following variables are used, (and in the case of the arrays,
0N/A * only initialised) for select fonts where a native scaler may be
0N/A * used to get glyph images and metrics.
0N/A * glyphToCharMap is filled in on the fly and used to do a reverse
0N/A * lookup when a FileFont needs to get the charcode back from a glyph
0N/A * code so it can re-map via a NativeGlyphMapper to get a native glyph.
0N/A * This isn't a big hit in time, since a boolean test is sufficient
0N/A * to choose the usual default path, nor in memory for fonts which take
0N/A * the native path, since fonts have contiguous zero-based glyph indexes,
0N/A * and these obviously do all exist in the font.
0N/A */
0N/A protected boolean checkedNatives;
0N/A protected boolean useNatives;
0N/A protected NativeFont[] nativeFonts;
0N/A protected char[] glyphToCharMap;
0N/A /*
0N/A * @throws FontFormatException - if the font can't be opened
0N/A */
0N/A FileFont(String platname, Object nativeNames)
0N/A throws FontFormatException {
0N/A
0N/A super(platname, nativeNames);
0N/A }
0N/A
0N/A FontStrike createStrike(FontStrikeDesc desc) {
0N/A if (!checkedNatives) {
0N/A checkUseNatives();
0N/A }
0N/A return new FileFontStrike(this, desc);
0N/A }
0N/A
0N/A protected boolean checkUseNatives() {
0N/A checkedNatives = true;
0N/A return useNatives;
0N/A }
0N/A
0N/A /* This method needs to be accessible to FontManager if there is
0N/A * file pool management. It may be a no-op.
0N/A */
0N/A protected abstract void close();
0N/A
0N/A
0N/A /*
0N/A * This is the public interface. The subclasses need to implement
0N/A * this. The returned block may be longer than the requested length.
0N/A */
0N/A abstract ByteBuffer readBlock(int offset, int length);
0N/A
0N/A public boolean canDoStyle(int style) {
0N/A return true;
0N/A }
0N/A
1121N/A void setFileToRemove(File file, CreatedFontTracker tracker) {
0N/A Disposer.addObjectRecord(this,
1121N/A new CreatedFontFileDisposerRecord(file, tracker));
0N/A }
0N/A
4632N/A // MACOSX begin -- Make this static so that we can pass in CFont
4632N/A static void setFileToRemove(Object font, File file, CreatedFontTracker tracker) {
4632N/A Disposer.addObjectRecord(font,
4632N/A new CreatedFontFileDisposerRecord(file, tracker));
4632N/A }
4632N/A // MACOSX - end
4632N/A
0N/A /* This is called when a font scaler is determined to
0N/A * be unusable (ie bad).
0N/A * We want to replace current scaler with NullFontScaler, so
0N/A * we never try to use same font scaler again.
0N/A * Scaler native resources could have already been disposed
0N/A * or they will be eventually by Java2D disposer.
0N/A * However, it should be safe to call dispose() explicitly here.
0N/A *
0N/A * For safety we also invalidate all strike's scaler context.
0N/A * So, in case they cache pointer to native scaler
0N/A * it will not ever be used.
0N/A *
0N/A * It also appears desirable to remove all the entries from the
0N/A * cache so no other code will pick them up. But we can't just
0N/A * 'delete' them as code may be using them. And simply dropping
0N/A * the reference to the cache will make the reference objects
0N/A * unreachable and so they will not get disposed.
0N/A * Since a strike may hold (via java arrays) native pointers to many
0N/A * rasterised glyphs, this would be a memory leak.
0N/A * The solution is :
0N/A * - to move all the entries to another map where they
0N/A * are no longer locatable
0N/A * - update FontStrikeDisposer to be able to distinguish which
0N/A * map they are held in via a boolean flag
0N/A * Since this isn't expected to be anything other than an extremely
0N/A * rare maybe it is not worth doing this last part.
0N/A */
0N/A synchronized void deregisterFontAndClearStrikeCache() {
1686N/A SunFontManager fm = SunFontManager.getInstance();
1686N/A fm.deRegisterBadFont(this);
0N/A
0N/A for (Reference strikeRef : strikeCache.values()) {
0N/A if (strikeRef != null) {
0N/A /* NB we know these are all FileFontStrike instances
0N/A * because the cache is on this FileFont
0N/A */
0N/A FileFontStrike strike = (FileFontStrike)strikeRef.get();
0N/A if (strike != null && strike.pScalerContext != 0L) {
0N/A scaler.invalidateScalerContext(strike.pScalerContext);
0N/A }
0N/A }
0N/A }
0N/A scaler.dispose();
1686N/A scaler = FontScaler.getNullScaler();
0N/A }
0N/A
0N/A StrikeMetrics getFontMetrics(long pScalerContext) {
0N/A try {
0N/A return getScaler().getFontMetrics(pScalerContext);
0N/A } catch (FontScalerException fe) {
1686N/A scaler = FontScaler.getNullScaler();
0N/A return getFontMetrics(pScalerContext);
0N/A }
0N/A }
0N/A
0N/A float getGlyphAdvance(long pScalerContext, int glyphCode) {
0N/A try {
0N/A return getScaler().getGlyphAdvance(pScalerContext, glyphCode);
0N/A } catch (FontScalerException fe) {
1686N/A scaler = FontScaler.getNullScaler();
0N/A return getGlyphAdvance(pScalerContext, glyphCode);
0N/A }
0N/A }
0N/A
0N/A void getGlyphMetrics(long pScalerContext, int glyphCode, Point2D.Float metrics) {
0N/A try {
0N/A getScaler().getGlyphMetrics(pScalerContext, glyphCode, metrics);
0N/A } catch (FontScalerException fe) {
1686N/A scaler = FontScaler.getNullScaler();
0N/A getGlyphMetrics(pScalerContext, glyphCode, metrics);
0N/A }
0N/A }
0N/A
0N/A long getGlyphImage(long pScalerContext, int glyphCode) {
0N/A try {
0N/A return getScaler().getGlyphImage(pScalerContext, glyphCode);
0N/A } catch (FontScalerException fe) {
1686N/A scaler = FontScaler.getNullScaler();
0N/A return getGlyphImage(pScalerContext, glyphCode);
0N/A }
0N/A }
0N/A
0N/A Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext, int glyphCode) {
0N/A try {
0N/A return getScaler().getGlyphOutlineBounds(pScalerContext, glyphCode);
0N/A } catch (FontScalerException fe) {
1686N/A scaler = FontScaler.getNullScaler();
0N/A return getGlyphOutlineBounds(pScalerContext, glyphCode);
0N/A }
0N/A }
0N/A
0N/A GeneralPath getGlyphOutline(long pScalerContext, int glyphCode, float x, float y) {
0N/A try {
0N/A return getScaler().getGlyphOutline(pScalerContext, glyphCode, x, y);
0N/A } catch (FontScalerException fe) {
1686N/A scaler = FontScaler.getNullScaler();
0N/A return getGlyphOutline(pScalerContext, glyphCode, x, y);
0N/A }
0N/A }
0N/A
0N/A GeneralPath getGlyphVectorOutline(long pScalerContext, int[] glyphs, int numGlyphs, float x, float y) {
0N/A try {
0N/A return getScaler().getGlyphVectorOutline(pScalerContext, glyphs, numGlyphs, x, y);
0N/A } catch (FontScalerException fe) {
1686N/A scaler = FontScaler.getNullScaler();
0N/A return getGlyphVectorOutline(pScalerContext, glyphs, numGlyphs, x, y);
0N/A }
0N/A }
0N/A
0N/A /* T1 & TT implementation differ so this method is abstract.
0N/A NB: null should not be returned here! */
0N/A protected abstract FontScaler getScaler();
0N/A
0N/A protected long getUnitsPerEm() {
0N/A return getScaler().getUnitsPerEm();
0N/A }
0N/A
1121N/A private static class CreatedFontFileDisposerRecord
1121N/A implements DisposerRecord {
0N/A
0N/A File fontFile = null;
1121N/A CreatedFontTracker tracker;
0N/A
1121N/A private CreatedFontFileDisposerRecord(File file,
1121N/A CreatedFontTracker tracker) {
0N/A fontFile = file;
1121N/A this.tracker = tracker;
0N/A }
0N/A
0N/A public void dispose() {
0N/A java.security.AccessController.doPrivileged(
0N/A new java.security.PrivilegedAction() {
0N/A public Object run() {
0N/A if (fontFile != null) {
0N/A try {
1121N/A if (tracker != null) {
1121N/A tracker.subBytes((int)fontFile.length());
1121N/A }
0N/A /* REMIND: is it possible that the file is
0N/A * still open? It will be closed when the
0N/A * font2D is disposed but could this code
0N/A * execute first? If so the file would not
0N/A * be deleted on MS-windows.
0N/A */
0N/A fontFile.delete();
0N/A /* remove from delete on exit hook list : */
1686N/A // FIXME: still need to be refactored
1686N/A SunFontManager.getInstance().tmpFontFiles.remove(fontFile);
0N/A } catch (Exception e) {
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A });
0N/A }
0N/A }
3784N/A
3784N/A protected String getPublicFileName() {
3784N/A SecurityManager sm = System.getSecurityManager();
3784N/A if (sm == null) {
3784N/A return platName;
3784N/A }
3784N/A boolean canReadProperty = true;
3784N/A
3784N/A try {
3784N/A sm.checkPropertyAccess("java.io.tmpdir");
3784N/A } catch (SecurityException e) {
3784N/A canReadProperty = false;
3784N/A }
3784N/A
3784N/A if (canReadProperty) {
3784N/A return platName;
3784N/A }
3784N/A
3784N/A final File f = new File(platName);
3784N/A
3784N/A Boolean isTmpFile = Boolean.FALSE;
3784N/A try {
3784N/A isTmpFile = AccessController.doPrivileged(
3784N/A new PrivilegedExceptionAction<Boolean>() {
3784N/A public Boolean run() {
3784N/A File tmp = new File(System.getProperty("java.io.tmpdir"));
3784N/A try {
3784N/A String tpath = tmp.getCanonicalPath();
3784N/A String fpath = f.getCanonicalPath();
3784N/A
3784N/A return (fpath == null) || fpath.startsWith(tpath);
3784N/A } catch (IOException e) {
3784N/A return Boolean.TRUE;
3784N/A }
3784N/A }
3784N/A }
3784N/A );
3784N/A } catch (PrivilegedActionException e) {
3784N/A // unable to verify whether value of java.io.tempdir will be
3784N/A // exposed, so return only a name of the font file.
3784N/A isTmpFile = Boolean.TRUE;
3784N/A }
3784N/A
3784N/A return isTmpFile ? "temp file" : platName;
3784N/A }
0N/A}