Path: blob/master/src/java.desktop/share/classes/sun/font/FileFont.java
41155 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.font;2627import java.lang.ref.Reference;28import java.awt.FontFormatException;29import java.awt.geom.GeneralPath;30import java.awt.geom.Point2D;31import java.awt.geom.Rectangle2D;32import java.io.File;33import java.nio.ByteBuffer;34import sun.java2d.Disposer;35import sun.java2d.DisposerRecord;3637import java.io.IOException;38import java.util.List;39import java.security.AccessController;40import java.security.PrivilegedActionException;41import java.security.PrivilegedExceptionAction;4243public abstract class FileFont extends PhysicalFont {4445protected boolean useJavaRasterizer = true;4647/* I/O and file operations are always synchronized on the font48* object. Two threads can be accessing the font and retrieving49* information, and synchronized only to the extent that filesystem50* operations require.51* A limited number of files can be open at a time, to limit the52* absorption of file descriptors. If a file needs to be opened53* when there are none free, then the synchronization of all I/O54* ensures that any in progress operation will complete before some55* 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 a58// 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 stream60// isn't needed ..61//protected FileInputStream stream;62//protected FileChannel channel;63protected int fileSize;6465protected FontScaler scaler;6667/* The following variables are used, (and in the case of the arrays,68* only initialised) for select fonts where a native scaler may be69* used to get glyph images and metrics.70* glyphToCharMap is filled in on the fly and used to do a reverse71* lookup when a FileFont needs to get the charcode back from a glyph72* 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 sufficient74* to choose the usual default path, nor in memory for fonts which take75* the native path, since fonts have contiguous zero-based glyph indexes,76* and these obviously do all exist in the font.77*/78protected NativeFont[] nativeFonts;79protected char[] glyphToCharMap;80/*81* @throws FontFormatException if the font can't be opened82*/83FileFont(String platname, Object nativeNames)84throws FontFormatException {8586super(platname, nativeNames);87}8889FontStrike createStrike(FontStrikeDesc desc) {90return new FileFontStrike(this, desc);91}9293/* This method needs to be accessible to FontManager if there is94* file pool management. It may be a no-op.95*/96protected abstract void close();979899/*100* This is the public interface. The subclasses need to implement101* this. The returned block may be longer than the requested length.102*/103abstract ByteBuffer readBlock(int offset, int length);104105public boolean canDoStyle(int style) {106return true;107}108109static void setFileToRemove(List<Font2D> fonts,110File file, int cnt,111CreatedFontTracker tracker)112{113CreatedFontFileDisposerRecord dr =114new CreatedFontFileDisposerRecord(file, cnt, tracker);115116for (Font2D f : fonts) {117Disposer.addObjectRecord(f, dr);118}119}120121/* This is called when a font scaler is determined to122* be unusable (ie bad).123* We want to replace current scaler with NullFontScaler, so124* we never try to use same font scaler again.125* Scaler native resources could have already been disposed126* or they will be eventually by Java2D disposer.127* However, it should be safe to call dispose() explicitly here.128*129* For safety we also invalidate all strike's scaler context.130* So, in case they cache pointer to native scaler131* it will not ever be used.132*133* It also appears desirable to remove all the entries from the134* cache so no other code will pick them up. But we can't just135* 'delete' them as code may be using them. And simply dropping136* the reference to the cache will make the reference objects137* unreachable and so they will not get disposed.138* Since a strike may hold (via java arrays) native pointers to many139* rasterised glyphs, this would be a memory leak.140* The solution is :141* - to move all the entries to another map where they142* are no longer locatable143* - update FontStrikeDisposer to be able to distinguish which144* map they are held in via a boolean flag145* Since this isn't expected to be anything other than an extremely146* rare maybe it is not worth doing this last part.147*/148synchronized void deregisterFontAndClearStrikeCache() {149SunFontManager fm = SunFontManager.getInstance();150fm.deRegisterBadFont(this);151152for (Reference<FontStrike> strikeRef : strikeCache.values()) {153if (strikeRef != null) {154/* NB we know these are all FileFontStrike instances155* because the cache is on this FileFont156*/157FileFontStrike strike = (FileFontStrike)strikeRef.get();158if (strike != null && strike.pScalerContext != 0L) {159scaler.invalidateScalerContext(strike.pScalerContext);160}161}162}163if (scaler != null) {164scaler.disposeScaler();165}166scaler = FontScaler.getNullScaler();167}168169StrikeMetrics getFontMetrics(long pScalerContext) {170try {171return getScaler().getFontMetrics(pScalerContext);172} catch (FontScalerException fe) {173scaler = FontScaler.getNullScaler();174return getFontMetrics(pScalerContext);175}176}177178float getGlyphAdvance(long pScalerContext, int glyphCode) {179try {180return getScaler().getGlyphAdvance(pScalerContext, glyphCode);181} catch (FontScalerException fe) {182scaler = FontScaler.getNullScaler();183return getGlyphAdvance(pScalerContext, glyphCode);184}185}186187void getGlyphMetrics(long pScalerContext, int glyphCode, Point2D.Float metrics) {188try {189getScaler().getGlyphMetrics(pScalerContext, glyphCode, metrics);190} catch (FontScalerException fe) {191scaler = FontScaler.getNullScaler();192getGlyphMetrics(pScalerContext, glyphCode, metrics);193}194}195196long getGlyphImage(long pScalerContext, int glyphCode) {197try {198return getScaler().getGlyphImage(pScalerContext, glyphCode);199} catch (FontScalerException fe) {200scaler = FontScaler.getNullScaler();201return getGlyphImage(pScalerContext, glyphCode);202}203}204205Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext, int glyphCode) {206try {207return getScaler().getGlyphOutlineBounds(pScalerContext, glyphCode);208} catch (FontScalerException fe) {209scaler = FontScaler.getNullScaler();210return getGlyphOutlineBounds(pScalerContext, glyphCode);211}212}213214GeneralPath getGlyphOutline(long pScalerContext, int glyphCode, float x, float y) {215try {216return getScaler().getGlyphOutline(pScalerContext, glyphCode, x, y);217} catch (FontScalerException fe) {218scaler = FontScaler.getNullScaler();219return getGlyphOutline(pScalerContext, glyphCode, x, y);220}221}222223GeneralPath getGlyphVectorOutline(long pScalerContext, int[] glyphs, int numGlyphs, float x, float y) {224try {225return getScaler().getGlyphVectorOutline(pScalerContext, glyphs, numGlyphs, x, y);226} catch (FontScalerException fe) {227scaler = FontScaler.getNullScaler();228return getGlyphVectorOutline(pScalerContext, glyphs, numGlyphs, x, y);229}230}231232/* T1 & TT implementation differ so this method is abstract.233NB: null should not be returned here! */234protected abstract FontScaler getScaler();235236protected long getUnitsPerEm() {237return getScaler().getUnitsPerEm();238}239240private static class CreatedFontFileDisposerRecord241implements DisposerRecord {242243File fontFile = null;244int count = 0; // number of fonts referencing this file object.245CreatedFontTracker tracker;246247private CreatedFontFileDisposerRecord(File file, int cnt,248CreatedFontTracker tracker) {249fontFile = file;250count = (cnt > 0) ? cnt : 1;251this.tracker = tracker;252}253254@SuppressWarnings("removal")255public void dispose() {256java.security.AccessController.doPrivileged(257new java.security.PrivilegedAction<Object>() {258public Object run() {259synchronized (fontFile) {260count--;261if (count > 0) {262return null;263}264}265if (fontFile != null) {266try {267if (tracker != null) {268tracker.subBytes((int)fontFile.length());269}270/* REMIND: is it possible that the file is271* still open? It will be closed when the272* font2D is disposed but could this code273* execute first? If so the file would not274* be deleted on MS-windows.275*/276fontFile.delete();277/* remove from delete on exit hook list : */278// FIXME: still need to be refactored279SunFontManager.getInstance().tmpFontFiles.remove(fontFile);280} catch (Exception e) {281}282}283return null;284}285});286}287}288289@SuppressWarnings("removal")290protected String getPublicFileName() {291SecurityManager sm = System.getSecurityManager();292if (sm == null) {293return platName;294}295boolean canReadProperty = true;296297try {298sm.checkPropertyAccess("java.io.tmpdir");299} catch (SecurityException e) {300canReadProperty = false;301}302303if (canReadProperty) {304return platName;305}306307final File f = new File(platName);308309Boolean isTmpFile = Boolean.FALSE;310try {311isTmpFile = AccessController.doPrivileged(312new PrivilegedExceptionAction<Boolean>() {313public Boolean run() {314File tmp = new File(System.getProperty("java.io.tmpdir"));315try {316String tpath = tmp.getCanonicalPath();317String fpath = f.getCanonicalPath();318319return (fpath == null) || fpath.startsWith(tpath);320} catch (IOException e) {321return Boolean.TRUE;322}323}324}325);326} catch (PrivilegedActionException e) {327// unable to verify whether value of java.io.tempdir will be328// exposed, so return only a name of the font file.329isTmpFile = Boolean.TRUE;330}331332return isTmpFile ? "temp file" : platName;333}334}335336337