blob: b6a2099d2a41ff1ac70c6e37d7697ff848c79e03 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.font;
27
28import java.lang.ref.Reference;
29import java.awt.FontFormatException;
30import java.awt.geom.GeneralPath;
31import java.awt.geom.Point2D;
32import java.awt.geom.Rectangle2D;
33import java.io.File;
34import java.nio.ByteBuffer;
35import java.nio.channels.FileChannel;
36import sun.java2d.Disposer;
37import sun.java2d.DisposerRecord;
38
39import java.lang.ref.WeakReference;
40import java.io.FileNotFoundException;
41import java.io.IOException;
42import java.io.RandomAccessFile;
43import java.io.UnsupportedEncodingException;
44import java.nio.ByteOrder;
45import java.nio.MappedByteBuffer;
46import java.nio.BufferUnderflowException;
47import java.nio.channels.ClosedChannelException;
48import java.util.HashSet;
49import java.util.HashMap;
50import java.awt.Font;
51
52public abstract class FileFont extends PhysicalFont {
53
54 protected boolean useJavaRasterizer = true;
55
56 /* I/O and file operations are always synchronized on the font
57 * object. Two threads can be accessing the font and retrieving
58 * information, and synchronized only to the extent that filesystem
59 * operations require.
60 * A limited number of files can be open at a time, to limit the
61 * absorption of file descriptors. If a file needs to be opened
62 * when there are none free, then the synchronization of all I/O
63 * ensures that any in progress operation will complete before some
64 * other thread closes the descriptor in order to allocate another one.
65 */
66 // NB consider using a RAF. FIS has finalize method so may take a
67 // little longer to be GC'd. We don't use this stream at all anyway.
68 // In fact why increase the size of a FileFont object if the stream
69 // isn't needed ..
70 //protected FileInputStream stream;
71 //protected FileChannel channel;
72 protected int fileSize;
73
74 protected FontScaler scaler;
75
76 /* The following variables are used, (and in the case of the arrays,
77 * only initialised) for select fonts where a native scaler may be
78 * used to get glyph images and metrics.
79 * glyphToCharMap is filled in on the fly and used to do a reverse
80 * lookup when a FileFont needs to get the charcode back from a glyph
81 * code so it can re-map via a NativeGlyphMapper to get a native glyph.
82 * This isn't a big hit in time, since a boolean test is sufficient
83 * to choose the usual default path, nor in memory for fonts which take
84 * the native path, since fonts have contiguous zero-based glyph indexes,
85 * and these obviously do all exist in the font.
86 */
87 protected boolean checkedNatives;
88 protected boolean useNatives;
89 protected NativeFont[] nativeFonts;
90 protected char[] glyphToCharMap;
91 /*
92 * @throws FontFormatException - if the font can't be opened
93 */
94 FileFont(String platname, Object nativeNames)
95 throws FontFormatException {
96
97 super(platname, nativeNames);
98 }
99
100 FontStrike createStrike(FontStrikeDesc desc) {
101 if (!checkedNatives) {
102 checkUseNatives();
103 }
104 return new FileFontStrike(this, desc);
105 }
106
107 protected boolean checkUseNatives() {
108 checkedNatives = true;
109 return useNatives;
110 }
111
112 /* This method needs to be accessible to FontManager if there is
113 * file pool management. It may be a no-op.
114 */
115 protected abstract void close();
116
117
118 /*
119 * This is the public interface. The subclasses need to implement
120 * this. The returned block may be longer than the requested length.
121 */
122 abstract ByteBuffer readBlock(int offset, int length);
123
124 public boolean canDoStyle(int style) {
125 return true;
126 }
127
128 void setFileToRemove(File file) {
129 Disposer.addObjectRecord(this,
130 new CreatedFontFileDisposerRecord(file));
131 }
132
133 /* This is called when a font scaler is determined to
134 * be unusable (ie bad).
135 * We want to replace current scaler with NullFontScaler, so
136 * we never try to use same font scaler again.
137 * Scaler native resources could have already been disposed
138 * or they will be eventually by Java2D disposer.
139 * However, it should be safe to call dispose() explicitly here.
140 *
141 * For safety we also invalidate all strike's scaler context.
142 * So, in case they cache pointer to native scaler
143 * it will not ever be used.
144 *
145 * It also appears desirable to remove all the entries from the
146 * cache so no other code will pick them up. But we can't just
147 * 'delete' them as code may be using them. And simply dropping
148 * the reference to the cache will make the reference objects
149 * unreachable and so they will not get disposed.
150 * Since a strike may hold (via java arrays) native pointers to many
151 * rasterised glyphs, this would be a memory leak.
152 * The solution is :
153 * - to move all the entries to another map where they
154 * are no longer locatable
155 * - update FontStrikeDisposer to be able to distinguish which
156 * map they are held in via a boolean flag
157 * Since this isn't expected to be anything other than an extremely
158 * rare maybe it is not worth doing this last part.
159 */
160 synchronized void deregisterFontAndClearStrikeCache() {
161 FontManager.deRegisterBadFont(this);
162
163 for (Reference strikeRef : strikeCache.values()) {
164 if (strikeRef != null) {
165 /* NB we know these are all FileFontStrike instances
166 * because the cache is on this FileFont
167 */
168 FileFontStrike strike = (FileFontStrike)strikeRef.get();
169 if (strike != null && strike.pScalerContext != 0L) {
170 scaler.invalidateScalerContext(strike.pScalerContext);
171 }
172 }
173 }
174 scaler.dispose();
175 scaler = FontManager.getNullScaler();
176 }
177
178 StrikeMetrics getFontMetrics(long pScalerContext) {
179 try {
180 return getScaler().getFontMetrics(pScalerContext);
181 } catch (FontScalerException fe) {
182 scaler = FontManager.getNullScaler();
183 return getFontMetrics(pScalerContext);
184 }
185 }
186
187 float getGlyphAdvance(long pScalerContext, int glyphCode) {
188 try {
189 return getScaler().getGlyphAdvance(pScalerContext, glyphCode);
190 } catch (FontScalerException fe) {
191 scaler = FontManager.getNullScaler();
192 return getGlyphAdvance(pScalerContext, glyphCode);
193 }
194 }
195
196 void getGlyphMetrics(long pScalerContext, int glyphCode, Point2D.Float metrics) {
197 try {
198 getScaler().getGlyphMetrics(pScalerContext, glyphCode, metrics);
199 } catch (FontScalerException fe) {
200 scaler = FontManager.getNullScaler();
201 getGlyphMetrics(pScalerContext, glyphCode, metrics);
202 }
203 }
204
205 long getGlyphImage(long pScalerContext, int glyphCode) {
206 try {
207 return getScaler().getGlyphImage(pScalerContext, glyphCode);
208 } catch (FontScalerException fe) {
209 scaler = FontManager.getNullScaler();
210 return getGlyphImage(pScalerContext, glyphCode);
211 }
212 }
213
214 Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext, int glyphCode) {
215 try {
216 return getScaler().getGlyphOutlineBounds(pScalerContext, glyphCode);
217 } catch (FontScalerException fe) {
218 scaler = FontManager.getNullScaler();
219 return getGlyphOutlineBounds(pScalerContext, glyphCode);
220 }
221 }
222
223 GeneralPath getGlyphOutline(long pScalerContext, int glyphCode, float x, float y) {
224 try {
225 return getScaler().getGlyphOutline(pScalerContext, glyphCode, x, y);
226 } catch (FontScalerException fe) {
227 scaler = FontManager.getNullScaler();
228 return getGlyphOutline(pScalerContext, glyphCode, x, y);
229 }
230 }
231
232 GeneralPath getGlyphVectorOutline(long pScalerContext, int[] glyphs, int numGlyphs, float x, float y) {
233 try {
234 return getScaler().getGlyphVectorOutline(pScalerContext, glyphs, numGlyphs, x, y);
235 } catch (FontScalerException fe) {
236 scaler = FontManager.getNullScaler();
237 return getGlyphVectorOutline(pScalerContext, glyphs, numGlyphs, x, y);
238 }
239 }
240
241 /* T1 & TT implementation differ so this method is abstract.
242 NB: null should not be returned here! */
243 protected abstract FontScaler getScaler();
244
245 protected long getUnitsPerEm() {
246 return getScaler().getUnitsPerEm();
247 }
248
249 private static class CreatedFontFileDisposerRecord implements DisposerRecord {
250
251 File fontFile = null;
252
253 private CreatedFontFileDisposerRecord(File file) {
254 fontFile = file;
255 }
256
257 public void dispose() {
258 java.security.AccessController.doPrivileged(
259 new java.security.PrivilegedAction() {
260 public Object run() {
261 if (fontFile != null) {
262 try {
263 /* REMIND: is it possible that the file is
264 * still open? It will be closed when the
265 * font2D is disposed but could this code
266 * execute first? If so the file would not
267 * be deleted on MS-windows.
268 */
269 fontFile.delete();
270 /* remove from delete on exit hook list : */
271 FontManager.tmpFontFiles.remove(fontFile);
272 } catch (Exception e) {
273 }
274 }
275 return null;
276 }
277 });
278 }
279 }
280}