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