1 /* 2 * Copyright (c) 2007, 2014, 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.awt.geom.GeneralPath; 29 import java.awt.geom.Point2D; 30 import java.awt.geom.Rectangle2D; 31 import java.lang.ref.WeakReference; 32 33 /* This is Freetype based implementation of FontScaler. 34 * 35 * Note that in case of runtime error it is expected that 36 * native code will release all native resources and 37 * call invalidateScaler() (that will throw FontScalerException). 38 * 39 * Note that callee is responsible for releasing native scaler context. 40 */ 41 class FreetypeFontScaler extends FontScaler { 42 /* constants aligned with native code */ 43 private static final int TRUETYPE_FONT = 1; 44 private static final int TYPE1_FONT = 2; 45 46 static { 47 /* At the moment fontmanager library depends on freetype library 48 and therefore no need to load it explicitly here */ FontManagerNativeLibrary.load()49 FontManagerNativeLibrary.load(); 50 initIDs(FreetypeFontScaler.class); 51 } 52 initIDs(Class<?> FFS)53 private static native void initIDs(Class<?> FFS); 54 invalidateScaler()55 private void invalidateScaler() throws FontScalerException { 56 nativeScaler = 0; 57 font = null; 58 throw new FontScalerException(); 59 } 60 FreetypeFontScaler(Font2D font, int indexInCollection, boolean supportsCJK, int filesize)61 public FreetypeFontScaler(Font2D font, int indexInCollection, 62 boolean supportsCJK, int filesize) { 63 int fonttype = TRUETYPE_FONT; 64 if (font instanceof Type1Font) { 65 fonttype = TYPE1_FONT; 66 } 67 nativeScaler = initNativeScaler(font, 68 fonttype, 69 indexInCollection, 70 supportsCJK, 71 filesize); 72 this.font = new WeakReference<>(font); 73 } 74 getFontMetrics(long pScalerContext)75 synchronized StrikeMetrics getFontMetrics(long pScalerContext) 76 throws FontScalerException { 77 if (nativeScaler != 0L) { 78 return getFontMetricsNative(font.get(), 79 pScalerContext, 80 nativeScaler); 81 } 82 return FontScaler.getNullScaler().getFontMetrics(0L); 83 } 84 getGlyphAdvance(long pScalerContext, int glyphCode)85 synchronized float getGlyphAdvance(long pScalerContext, int glyphCode) 86 throws FontScalerException { 87 if (nativeScaler != 0L) { 88 return getGlyphAdvanceNative(font.get(), 89 pScalerContext, 90 nativeScaler, 91 glyphCode); 92 } 93 return FontScaler.getNullScaler(). 94 getGlyphAdvance(0L, glyphCode); 95 } 96 getGlyphMetrics(long pScalerContext, int glyphCode, Point2D.Float metrics)97 synchronized void getGlyphMetrics(long pScalerContext, 98 int glyphCode, Point2D.Float metrics) 99 throws FontScalerException { 100 if (nativeScaler != 0L) { 101 getGlyphMetricsNative(font.get(), 102 pScalerContext, 103 nativeScaler, 104 glyphCode, 105 metrics); 106 return; 107 } 108 FontScaler.getNullScaler(). 109 getGlyphMetrics(0L, glyphCode, metrics); 110 } 111 getGlyphImage(long pScalerContext, int glyphCode)112 synchronized long getGlyphImage(long pScalerContext, int glyphCode) 113 throws FontScalerException { 114 if (nativeScaler != 0L) { 115 return getGlyphImageNative(font.get(), 116 pScalerContext, 117 nativeScaler, 118 glyphCode); 119 } 120 return FontScaler.getNullScaler(). 121 getGlyphImage(0L, glyphCode); 122 } 123 getGlyphOutlineBounds( long pScalerContext, int glyphCode)124 synchronized Rectangle2D.Float getGlyphOutlineBounds( 125 long pScalerContext, int glyphCode) 126 throws FontScalerException { 127 if (nativeScaler != 0L) { 128 return getGlyphOutlineBoundsNative(font.get(), 129 pScalerContext, 130 nativeScaler, 131 glyphCode); 132 } 133 return FontScaler.getNullScaler(). 134 getGlyphOutlineBounds(0L,glyphCode); 135 } 136 getGlyphOutline( long pScalerContext, int glyphCode, float x, float y)137 synchronized GeneralPath getGlyphOutline( 138 long pScalerContext, int glyphCode, float x, float y) 139 throws FontScalerException { 140 if (nativeScaler != 0L) { 141 return getGlyphOutlineNative(font.get(), 142 pScalerContext, 143 nativeScaler, 144 glyphCode, 145 x, y); 146 } 147 return FontScaler.getNullScaler(). 148 getGlyphOutline(0L, glyphCode, x,y); 149 } 150 getGlyphVectorOutline( long pScalerContext, int[] glyphs, int numGlyphs, float x, float y)151 synchronized GeneralPath getGlyphVectorOutline( 152 long pScalerContext, int[] glyphs, int numGlyphs, 153 float x, float y) throws FontScalerException { 154 if (nativeScaler != 0L) { 155 return getGlyphVectorOutlineNative(font.get(), 156 pScalerContext, 157 nativeScaler, 158 glyphs, 159 numGlyphs, 160 x, y); 161 } 162 return FontScaler 163 .getNullScaler().getGlyphVectorOutline(0L, glyphs, numGlyphs, x, y); 164 } 165 166 /* This method should not be called directly, in case 167 * it is being invoked from a thread with a native context. 168 */ dispose()169 public synchronized void dispose() { 170 if (nativeScaler != 0L) { 171 disposeNativeScaler(font.get(), nativeScaler); 172 nativeScaler = 0L; 173 } 174 } 175 disposeScaler()176 public synchronized void disposeScaler() { 177 if (nativeScaler != 0L) { 178 /* 179 * The current thread may be calling this method from the context 180 * of a JNI up-call. It will hold the native lock from the 181 * original down-call so can directly enter dispose and free 182 * the resources. So we need to schedule the disposal to happen 183 * only once we've returned from native. So by running the dispose 184 * on another thread which does nothing except that disposal we 185 * are sure that this is safe. 186 */ 187 new Thread(null, () -> dispose(), "free scaler", 0, false).start(); 188 } 189 } 190 getNumGlyphs()191 synchronized int getNumGlyphs() throws FontScalerException { 192 if (nativeScaler != 0L) { 193 return getNumGlyphsNative(nativeScaler); 194 } 195 return FontScaler.getNullScaler().getNumGlyphs(); 196 } 197 getMissingGlyphCode()198 synchronized int getMissingGlyphCode() throws FontScalerException { 199 if (nativeScaler != 0L) { 200 return getMissingGlyphCodeNative(nativeScaler); 201 } 202 return FontScaler.getNullScaler().getMissingGlyphCode(); 203 } 204 getGlyphCode(char charCode)205 synchronized int getGlyphCode(char charCode) throws FontScalerException { 206 if (nativeScaler != 0L) { 207 return getGlyphCodeNative(font.get(), nativeScaler, charCode); 208 } 209 return FontScaler.getNullScaler().getGlyphCode(charCode); 210 } 211 getGlyphPoint(long pScalerContext, int glyphCode, int ptNumber)212 synchronized Point2D.Float getGlyphPoint(long pScalerContext, 213 int glyphCode, int ptNumber) 214 throws FontScalerException { 215 if (nativeScaler != 0L) { 216 return getGlyphPointNative(font.get(), pScalerContext, 217 nativeScaler, glyphCode, ptNumber); 218 } 219 return FontScaler.getNullScaler().getGlyphPoint( 220 pScalerContext, glyphCode, ptNumber); 221 } 222 getUnitsPerEm()223 synchronized long getUnitsPerEm() { 224 return getUnitsPerEMNative(nativeScaler); 225 } 226 createScalerContext(double[] matrix, int aa, int fm, float boldness, float italic, boolean disableHinting)227 synchronized long createScalerContext(double[] matrix, 228 int aa, int fm, float boldness, float italic, 229 boolean disableHinting) { 230 if (nativeScaler != 0L) { 231 return createScalerContextNative(nativeScaler, matrix, 232 aa, fm, boldness, italic); 233 } 234 return NullFontScaler.getNullScalerContext(); 235 } 236 237 //Note: native methods can throw RuntimeException if processing fails initNativeScaler(Font2D font, int type, int indexInCollection, boolean supportsCJK, int filesize)238 private native long initNativeScaler(Font2D font, int type, 239 int indexInCollection, boolean supportsCJK, int filesize); getFontMetricsNative(Font2D font, long pScalerContext, long pScaler)240 private native StrikeMetrics getFontMetricsNative(Font2D font, 241 long pScalerContext, long pScaler); getGlyphAdvanceNative(Font2D font, long pScalerContext, long pScaler, int glyphCode)242 private native float getGlyphAdvanceNative(Font2D font, 243 long pScalerContext, long pScaler, int glyphCode); getGlyphMetricsNative(Font2D font, long pScalerContext, long pScaler, int glyphCode, Point2D.Float metrics)244 private native void getGlyphMetricsNative(Font2D font, 245 long pScalerContext, long pScaler, 246 int glyphCode, Point2D.Float metrics); getGlyphImageNative(Font2D font, long pScalerContext, long pScaler, int glyphCode)247 private native long getGlyphImageNative(Font2D font, 248 long pScalerContext, long pScaler, int glyphCode); getGlyphOutlineBoundsNative(Font2D font, long pScalerContext, long pScaler, int glyphCode)249 private native Rectangle2D.Float getGlyphOutlineBoundsNative(Font2D font, 250 long pScalerContext, long pScaler, int glyphCode); getGlyphOutlineNative(Font2D font, long pScalerContext, long pScaler, int glyphCode, float x, float y)251 private native GeneralPath getGlyphOutlineNative(Font2D font, 252 long pScalerContext, long pScaler, 253 int glyphCode, float x, float y); getGlyphVectorOutlineNative(Font2D font, long pScalerContext, long pScaler, int[] glyphs, int numGlyphs, float x, float y)254 private native GeneralPath getGlyphVectorOutlineNative(Font2D font, 255 long pScalerContext, long pScaler, 256 int[] glyphs, int numGlyphs, float x, float y); getGlyphPointNative(Font2D font, long pScalerContext, long pScaler, int glyphCode, int ptNumber)257 private native Point2D.Float getGlyphPointNative(Font2D font, 258 long pScalerContext, long pScaler, int glyphCode, int ptNumber); 259 disposeNativeScaler(Font2D font2D, long pScaler)260 private native void disposeNativeScaler(Font2D font2D, long pScaler); 261 getGlyphCodeNative(Font2D font, long pScaler, char charCode)262 private native int getGlyphCodeNative(Font2D font, long pScaler, char charCode); getNumGlyphsNative(long pScaler)263 private native int getNumGlyphsNative(long pScaler); getMissingGlyphCodeNative(long pScaler)264 private native int getMissingGlyphCodeNative(long pScaler); 265 getUnitsPerEMNative(long pScaler)266 private native long getUnitsPerEMNative(long pScaler); 267 createScalerContextNative(long pScaler, double[] matrix, int aa, int fm, float boldness, float italic)268 private native long createScalerContextNative(long pScaler, double[] matrix, 269 int aa, int fm, float boldness, float italic); 270 271 /* Freetype scaler context does not contain any pointers that 272 has to be invalidated if native scaler is bad */ invalidateScalerContext(long pScalerContext)273 void invalidateScalerContext(long pScalerContext) {} 274 } 275