Showing the changes to java/pkg/sun/font/FileFont.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,325 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2003, 2010, Oracle and/or its affiliates. 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. Oracle designates this | ||
| 8 | * particular file as subject to the "Classpath" exception as provided | ||
| 9 | * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| 22 | * or visit www.oracle.com if you need additional information or have any | ||
| 23 | * questions. | ||
| 24 | */ | ||
| 25 | |||
| 26 | package sun.font; | ||
| 27 | |||
| 28 | import java.lang.ref.Reference; | ||
| 29 | import java.awt.FontFormatException; | ||
| 30 | import java.awt.geom.GeneralPath; | ||
| 31 | import java.awt.geom.Point2D; | ||
| 32 | import java.awt.geom.Rectangle2D; | ||
| 33 | import java.io.File; | ||
| 34 | import java.nio.ByteBuffer; | ||
| 35 | import sun.java2d.Disposer; | ||
| 36 | import sun.java2d.DisposerRecord; | ||
| 37 | |||
| 38 | import java.io.IOException; | ||
| 39 | import java.security.AccessController; | ||
| 40 | import java.security.PrivilegedActionException; | ||
| 41 | import java.security.PrivilegedExceptionAction; | ||
| 42 | |||
| 43 | public abstract class FileFont extends PhysicalFont { | ||
| 44 | |||
| 45 | protected boolean useJavaRasterizer = true; | ||
| 46 | |||
| 47 | /* I/O and file operations are always synchronized on the font | ||
| 48 | * object. Two threads can be accessing the font and retrieving | ||
| 49 | * information, and synchronized only to the extent that filesystem | ||
| 50 | * operations require. | ||
| 51 | * A limited number of files can be open at a time, to limit the | ||
| 52 | * absorption of file descriptors. If a file needs to be opened | ||
| 53 | * when there are none free, then the synchronization of all I/O | ||
| 54 | * ensures that any in progress operation will complete before some | ||
| 55 | * other thread closes the descriptor in order to allocate another one. | ||
| 56 | */ | ||
| 57 | // NB consider using a RAF. FIS has finalize method so may take a | ||
| 58 | // little longer to be GC'd. We don't use this stream at all anyway. | ||
| 59 | // In fact why increase the size of a FileFont object if the stream | ||
| 60 | // isn't needed .. | ||
| 61 | //protected FileInputStream stream; | ||
| 62 | //protected FileChannel channel; | ||
| 63 | protected int fileSize; | ||
| 64 | |||
| 65 | protected FontScaler scaler; | ||
| 66 | |||
| 67 | /* The following variables are used, (and in the case of the arrays, | ||
| 68 | * only initialised) for select fonts where a native scaler may be | ||
| 69 | * used to get glyph images and metrics. | ||
| 70 | * glyphToCharMap is filled in on the fly and used to do a reverse | ||
| 71 | * lookup when a FileFont needs to get the charcode back from a glyph | ||
| 72 | * code so it can re-map via a NativeGlyphMapper to get a native glyph. | ||
| 73 | * This isn't a big hit in time, since a boolean test is sufficient | ||
| 74 | * to choose the usual default path, nor in memory for fonts which take | ||
| 75 | * the native path, since fonts have contiguous zero-based glyph indexes, | ||
| 76 | * and these obviously do all exist in the font. | ||
| 77 | */ | ||
| 78 | protected boolean checkedNatives; | ||
| 79 | protected boolean useNatives; | ||
| 80 | protected NativeFont[] nativeFonts; | ||
| 81 | protected char[] glyphToCharMap; | ||
| 82 | /* | ||
| 83 | * @throws FontFormatException - if the font can't be opened | ||
| 84 | */ | ||
| 85 | FileFont(String platname, Object nativeNames) | ||
| 86 | throws FontFormatException { | ||
| 87 | |||
| 88 | super(platname, nativeNames); | ||
| 89 | } | ||
| 90 | |||
| 91 | FontStrike createStrike(FontStrikeDesc desc) { | ||
| 92 | if (!checkedNatives) { | ||
| 93 | checkUseNatives(); | ||
| 94 | } | ||
| 95 | return new FileFontStrike(this, desc); | ||
| 96 | } | ||
| 97 | |||
| 98 | protected boolean checkUseNatives() { | ||
| 99 | checkedNatives = true; | ||
| 100 | return useNatives; | ||
| 101 | } | ||
| 102 | |||
| 103 | /* This method needs to be accessible to FontManager if there is | ||
| 104 | * file pool management. It may be a no-op. | ||
| 105 | */ | ||
| 106 | protected abstract void close(); | ||
| 107 | |||
| 108 | |||
| 109 | /* | ||
| 110 | * This is the public interface. The subclasses need to implement | ||
| 111 | * this. The returned block may be longer than the requested length. | ||
| 112 | */ | ||
| 113 | abstract ByteBuffer readBlock(int offset, int length); | ||
| 114 | |||
| 115 | public boolean canDoStyle(int style) { | ||
| 116 | return true; | ||
| 117 | } | ||
| 118 | |||
| 119 | void setFileToRemove(File file, CreatedFontTracker tracker) { | ||
| 120 | Disposer.addObjectRecord(this, | ||
| 121 | new CreatedFontFileDisposerRecord(file, tracker)); | ||
| 122 | } | ||
| 123 | |||
| 124 | /* This is called when a font scaler is determined to | ||
| 125 | * be unusable (ie bad). | ||
| 126 | * We want to replace current scaler with NullFontScaler, so | ||
| 127 | * we never try to use same font scaler again. | ||
| 128 | * Scaler native resources could have already been disposed | ||
| 129 | * or they will be eventually by Java2D disposer. | ||
| 130 | * However, it should be safe to call dispose() explicitly here. | ||
| 131 | * | ||
| 132 | * For safety we also invalidate all strike's scaler context. | ||
| 133 | * So, in case they cache pointer to native scaler | ||
| 134 | * it will not ever be used. | ||
| 135 | * | ||
| 136 | * It also appears desirable to remove all the entries from the | ||
| 137 | * cache so no other code will pick them up. But we can't just | ||
| 138 | * 'delete' them as code may be using them. And simply dropping | ||
| 139 | * the reference to the cache will make the reference objects | ||
| 140 | * unreachable and so they will not get disposed. | ||
| 141 | * Since a strike may hold (via java arrays) native pointers to many | ||
| 142 | * rasterised glyphs, this would be a memory leak. | ||
| 143 | * The solution is : | ||
| 144 | * - to move all the entries to another map where they | ||
| 145 | * are no longer locatable | ||
| 146 | * - update FontStrikeDisposer to be able to distinguish which | ||
| 147 | * map they are held in via a boolean flag | ||
| 148 | * Since this isn't expected to be anything other than an extremely | ||
| 149 | * rare maybe it is not worth doing this last part. | ||
| 150 | */ | ||
| 151 | synchronized void deregisterFontAndClearStrikeCache() { | ||
| 152 | SunFontManager fm = SunFontManager.getInstance(); | ||
| 153 | fm.deRegisterBadFont(this); | ||
| 154 | |||
| 155 | for (Reference strikeRef : strikeCache.values()) { | ||
| 156 | if (strikeRef != null) { | ||
| 157 | /* NB we know these are all FileFontStrike instances | ||
| 158 | * because the cache is on this FileFont | ||
| 159 | */ | ||
| 160 | FileFontStrike strike = (FileFontStrike)strikeRef.get(); | ||
| 161 | if (strike != null && strike.pScalerContext != 0L) { | ||
| 162 | scaler.invalidateScalerContext(strike.pScalerContext); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 166 | scaler.dispose(); | ||
| 167 | scaler = FontScaler.getNullScaler(); | ||
| 168 | } | ||
| 169 | |||
| 170 | StrikeMetrics getFontMetrics(long pScalerContext) { | ||
| 171 | try { | ||
| 172 | return getScaler().getFontMetrics(pScalerContext); | ||
| 173 | } catch (FontScalerException fe) { | ||
| 174 | scaler = FontScaler.getNullScaler(); | ||
| 175 | return getFontMetrics(pScalerContext); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | float getGlyphAdvance(long pScalerContext, int glyphCode) { | ||
| 180 | try { | ||
| 181 | return getScaler().getGlyphAdvance(pScalerContext, glyphCode); | ||
| 182 | } catch (FontScalerException fe) { | ||
| 183 | scaler = FontScaler.getNullScaler(); | ||
| 184 | return getGlyphAdvance(pScalerContext, glyphCode); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | void getGlyphMetrics(long pScalerContext, int glyphCode, Point2D.Float metrics) { | ||
| 189 | try { | ||
| 190 | getScaler().getGlyphMetrics(pScalerContext, glyphCode, metrics); | ||
| 191 | } catch (FontScalerException fe) { | ||
| 192 | scaler = FontScaler.getNullScaler(); | ||
| 193 | getGlyphMetrics(pScalerContext, glyphCode, metrics); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | long getGlyphImage(long pScalerContext, int glyphCode) { | ||
| 198 | try { | ||
| 199 | return getScaler().getGlyphImage(pScalerContext, glyphCode); | ||
| 200 | } catch (FontScalerException fe) { | ||
| 201 | scaler = FontScaler.getNullScaler(); | ||
| 202 | return getGlyphImage(pScalerContext, glyphCode); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext, int glyphCode) { | ||
| 207 | try { | ||
| 208 | return getScaler().getGlyphOutlineBounds(pScalerContext, glyphCode); | ||
| 209 | } catch (FontScalerException fe) { | ||
| 210 | scaler = FontScaler.getNullScaler(); | ||
| 211 | return getGlyphOutlineBounds(pScalerContext, glyphCode); | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | GeneralPath getGlyphOutline(long pScalerContext, int glyphCode, float x, float y) { | ||
| 216 | try { | ||
| 217 | return getScaler().getGlyphOutline(pScalerContext, glyphCode, x, y); | ||
| 218 | } catch (FontScalerException fe) { | ||
| 219 | scaler = FontScaler.getNullScaler(); | ||
| 220 | return getGlyphOutline(pScalerContext, glyphCode, x, y); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | GeneralPath getGlyphVectorOutline(long pScalerContext, int[] glyphs, int numGlyphs, float x, float y) { | ||
| 225 | try { | ||
| 226 | return getScaler().getGlyphVectorOutline(pScalerContext, glyphs, numGlyphs, x, y); | ||
| 227 | } catch (FontScalerException fe) { | ||
| 228 | scaler = FontScaler.getNullScaler(); | ||
| 229 | return getGlyphVectorOutline(pScalerContext, glyphs, numGlyphs, x, y); | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | /* T1 & TT implementation differ so this method is abstract. | ||
| 234 | NB: null should not be returned here! */ | ||
| 235 | protected abstract FontScaler getScaler(); | ||
| 236 | |||
| 237 | protected long getUnitsPerEm() { | ||
| 238 | return getScaler().getUnitsPerEm(); | ||
| 239 | } | ||
| 240 | |||
| 241 | private static class CreatedFontFileDisposerRecord | ||
| 242 | implements DisposerRecord { | ||
| 243 | |||
| 244 | File fontFile = null; | ||
| 245 | CreatedFontTracker tracker; | ||
| 246 | |||
| 247 | private CreatedFontFileDisposerRecord(File file, | ||
| 248 | CreatedFontTracker tracker) { | ||
| 249 | fontFile = file; | ||
| 250 | this.tracker = tracker; | ||
| 251 | } | ||
| 252 | |||
| 253 | public void dispose() { | ||
| 254 | java.security.AccessController.doPrivileged( | ||
| 255 | new java.security.PrivilegedAction() { | ||
| 256 | public Object run() { | ||
| 257 | if (fontFile != null) { | ||
| 258 | try { | ||
| 259 | if (tracker != null) { | ||
| 260 | tracker.subBytes((int)fontFile.length()); | ||
| 261 | } | ||
| 262 | /* REMIND: is it possible that the file is | ||
| 263 | * still open? It will be closed when the | ||
| 264 | * font2D is disposed but could this code | ||
| 265 | * execute first? If so the file would not | ||
| 266 | * be deleted on MS-windows. | ||
| 267 | */ | ||
| 268 | fontFile.delete(); | ||
| 269 | /* remove from delete on exit hook list : */ | ||
| 270 | // FIXME: still need to be refactored | ||
| 271 | SunFontManager.getInstance().tmpFontFiles.remove(fontFile); | ||
| 272 | } catch (Exception e) { | ||
| 273 | } | ||
| 274 | } | ||
| 275 | return null; | ||
| 276 | } | ||
| 277 | }); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | protected String getPublicFileName() { | ||
| 282 | SecurityManager sm = System.getSecurityManager(); | ||
| 283 | if (sm == null) { | ||
| 284 | return platName; | ||
| 285 | } | ||
| 286 | boolean canReadProperty = true; | ||
| 287 | |||
| 288 | try { | ||
| 289 | sm.checkPropertyAccess("java.io.tmpdir"); | ||
| 290 | } catch (SecurityException e) { | ||
| 291 | canReadProperty = false; | ||
| 292 | } | ||
| 293 | |||
| 294 | if (canReadProperty) { | ||
| 295 | return platName; | ||
| 296 | } | ||
| 297 | |||
| 298 | final File f = new File(platName); | ||
| 299 | |||
| 300 | Boolean isTmpFile = Boolean.FALSE; | ||
| 301 | try { | ||
| 302 | isTmpFile = AccessController.doPrivileged( | ||
| 303 | new PrivilegedExceptionAction<Boolean>() { | ||
| 304 | public Boolean run() { | ||
| 305 | File tmp = new File(System.getProperty("java.io.tmpdir")); | ||
| 306 | try { | ||
| 307 | String tpath = tmp.getCanonicalPath(); | ||
| 308 | String fpath = f.getCanonicalPath(); | ||
| 309 | |||
| 310 | return (fpath == null) || fpath.startsWith(tpath); | ||
| 311 | } catch (IOException e) { | ||
| 312 | return Boolean.TRUE; | ||
| 313 | } | ||
| 314 | } | ||
| 315 | } | ||
| 316 | ); | ||
| 317 | } catch (PrivilegedActionException e) { | ||
| 318 | // unable to verify whether value of java.io.tempdir will be | ||
| 319 | // exposed, so return only a name of the font file. | ||
| 320 | isTmpFile = Boolean.TRUE; | ||
| 321 | } | ||
| 322 | |||
| 323 | return isTmpFile ? "temp file" : platName; | ||
| 324 | } | ||
| 325 | } | ||