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
26package sun.font;
27
28import java.awt.geom.GeneralPath;
29import java.awt.geom.Point2D;
30import java.awt.geom.Rectangle2D;
31import 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 */
41class 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 */
49        FontManagerNativeLibrary.load();
50        initIDs(FreetypeFontScaler.class);
51    }
52
53    private static native void initIDs(Class<?> FFS);
54
55    private void invalidateScaler() throws FontScalerException {
56        nativeScaler = 0;
57        font = null;
58        throw new FontScalerException();
59    }
60
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
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
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
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
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
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
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
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    synchronized long getLayoutTableCache() throws FontScalerException {
167        return getLayoutTableCacheNative(nativeScaler);
168    }
169
170    public synchronized void dispose() {
171        if (nativeScaler != 0L) {
172            disposeNativeScaler(font.get(), nativeScaler);
173            nativeScaler = 0L;
174        }
175    }
176
177    synchronized int getNumGlyphs() throws FontScalerException {
178        if (nativeScaler != 0L) {
179            return getNumGlyphsNative(nativeScaler);
180        }
181        return FontScaler.getNullScaler().getNumGlyphs();
182    }
183
184    synchronized int getMissingGlyphCode()  throws FontScalerException {
185        if (nativeScaler != 0L) {
186            return getMissingGlyphCodeNative(nativeScaler);
187        }
188        return FontScaler.getNullScaler().getMissingGlyphCode();
189    }
190
191    synchronized int getGlyphCode(char charCode) throws FontScalerException {
192        if (nativeScaler != 0L) {
193            return getGlyphCodeNative(font.get(), nativeScaler, charCode);
194        }
195        return FontScaler.getNullScaler().getGlyphCode(charCode);
196    }
197
198    synchronized Point2D.Float getGlyphPoint(long pScalerContext,
199                                       int glyphCode, int ptNumber)
200                               throws FontScalerException {
201        if (nativeScaler != 0L) {
202            return getGlyphPointNative(font.get(), pScalerContext,
203                                      nativeScaler, glyphCode, ptNumber);
204        }
205        return FontScaler.getNullScaler().getGlyphPoint(
206                   pScalerContext, glyphCode,  ptNumber);
207    }
208
209    synchronized long getUnitsPerEm() {
210        return getUnitsPerEMNative(nativeScaler);
211    }
212
213    long createScalerContext(double[] matrix,
214            int aa, int fm, float boldness, float italic,
215            boolean disableHinting) {
216        if (nativeScaler != 0L) {
217            return createScalerContextNative(nativeScaler, matrix,
218                                             aa, fm, boldness, italic);
219        }
220        return NullFontScaler.getNullScalerContext();
221    }
222
223    //Note: native methods can throw RuntimeException if processing fails
224    private native long initNativeScaler(Font2D font, int type,
225            int indexInCollection, boolean supportsCJK, int filesize);
226    private native StrikeMetrics getFontMetricsNative(Font2D font,
227            long pScalerContext, long pScaler);
228    private native float getGlyphAdvanceNative(Font2D font,
229            long pScalerContext, long pScaler, int glyphCode);
230    private native void getGlyphMetricsNative(Font2D font,
231            long pScalerContext, long pScaler,
232            int glyphCode, Point2D.Float metrics);
233    private native long getGlyphImageNative(Font2D font,
234            long pScalerContext, long pScaler, int glyphCode);
235    private native Rectangle2D.Float getGlyphOutlineBoundsNative(Font2D font,
236            long pScalerContext, long pScaler, int glyphCode);
237    private native GeneralPath getGlyphOutlineNative(Font2D font,
238            long pScalerContext, long pScaler,
239            int glyphCode, float x, float y);
240    private native GeneralPath getGlyphVectorOutlineNative(Font2D font,
241            long pScalerContext, long pScaler,
242            int[] glyphs, int numGlyphs, float x, float y);
243    native Point2D.Float getGlyphPointNative(Font2D font,
244            long pScalerContext, long pScaler, int glyphCode, int ptNumber);
245
246    private native long getLayoutTableCacheNative(long pScaler);
247
248    private native void disposeNativeScaler(Font2D font2D, long pScaler);
249
250    private native int getGlyphCodeNative(Font2D font, long pScaler, char charCode);
251    private native int getNumGlyphsNative(long pScaler);
252    private native int getMissingGlyphCodeNative(long pScaler);
253
254    private native long getUnitsPerEMNative(long pScaler);
255
256    native long createScalerContextNative(long pScaler, double[] matrix,
257            int aa, int fm, float boldness, float italic);
258
259    /* Freetype scaler context does not contain any pointers that
260       has to be invalidated if native scaler is bad */
261    void invalidateScalerContext(long pScalerContext) {}
262}
263