1 /*
   2  * Copyright (c) 2007 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any 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 */
  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 FontManager.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 FontManager.getNullScaler().getGlyphAdvance(0L, glyphCode);
  94     }
  95 
  96     synchronized void getGlyphMetrics(long pScalerContext,
  97                      int glyphCode, Point2D.Float metrics)
  98                      throws FontScalerException {
  99         if (nativeScaler != 0L) {
 100             getGlyphMetricsNative(font.get(),
 101                                   pScalerContext,
 102                                   nativeScaler,
 103                                   glyphCode,
 104                                   metrics);
 105             return;
 106         }
 107         FontManager.getNullScaler().getGlyphMetrics(0L, glyphCode, metrics);
 108     }
 109 
 110     synchronized long getGlyphImage(long pScalerContext, int glyphCode)
 111                      throws FontScalerException {
 112         if (nativeScaler != 0L) {
 113             return getGlyphImageNative(font.get(),
 114                                        pScalerContext,
 115                                        nativeScaler,
 116                                        glyphCode);
 117         }
 118         return FontManager.getNullScaler().getGlyphImage(0L, glyphCode);
 119     }
 120 
 121     synchronized Rectangle2D.Float getGlyphOutlineBounds(
 122                      long pScalerContext, int glyphCode)
 123                      throws FontScalerException {
 124         if (nativeScaler != 0L) {
 125             return getGlyphOutlineBoundsNative(font.get(),
 126                                                pScalerContext,
 127                                                nativeScaler,
 128                                                glyphCode);
 129         }
 130         return FontManager.getNullScaler().getGlyphOutlineBounds(0L,glyphCode);
 131     }
 132 
 133     synchronized GeneralPath getGlyphOutline(
 134                      long pScalerContext, int glyphCode, float x, float y)
 135                      throws FontScalerException {
 136         if (nativeScaler != 0L) {
 137             return getGlyphOutlineNative(font.get(),
 138                                          pScalerContext,
 139                                          nativeScaler,
 140                                          glyphCode,
 141                                          x, y);
 142         }
 143         return FontManager.getNullScaler().getGlyphOutline(0L, glyphCode, x,y);
 144     }
 145 
 146     synchronized GeneralPath getGlyphVectorOutline(
 147                      long pScalerContext, int[] glyphs, int numGlyphs,
 148                      float x, float y) throws FontScalerException {
 149         if (nativeScaler != 0L) {
 150             return getGlyphVectorOutlineNative(font.get(),
 151                                                pScalerContext,
 152                                                nativeScaler,
 153                                                glyphs,
 154                                                numGlyphs,
 155                                                x, y);
 156         }
 157         return FontManager.getNullScaler().getGlyphVectorOutline(
 158                    0L, glyphs, numGlyphs, x, y);
 159     }
 160 
 161     synchronized long getLayoutTableCache() throws FontScalerException {
 162         return getLayoutTableCacheNative(nativeScaler);
 163     }
 164 
 165     public synchronized void dispose() {
 166         if (nativeScaler != 0L) {
 167             disposeNativeScaler(nativeScaler);
 168             nativeScaler = 0L;
 169         }
 170     }
 171 
 172     synchronized int getNumGlyphs() throws FontScalerException {
 173         if (nativeScaler != 0L) {
 174             return getNumGlyphsNative(nativeScaler);
 175         }
 176         return FontManager.getNullScaler().getNumGlyphs();
 177     }
 178 
 179     synchronized int getMissingGlyphCode()  throws FontScalerException {
 180         if (nativeScaler != 0L) {
 181             return getMissingGlyphCodeNative(nativeScaler);
 182         }
 183         return FontManager.getNullScaler().getMissingGlyphCode();
 184     }
 185 
 186     synchronized int getGlyphCode(char charCode) throws FontScalerException {
 187         if (nativeScaler != 0L) {
 188             return getGlyphCodeNative(nativeScaler, charCode);
 189         }
 190         return FontManager.getNullScaler().getGlyphCode(charCode);
 191     }
 192 
 193     synchronized Point2D.Float getGlyphPoint(long pScalerContext,
 194                                        int glyphCode, int ptNumber)
 195                                throws FontScalerException {
 196         if (nativeScaler != 0L) {
 197             return getGlyphPointNative(font.get(), pScalerContext,
 198                                       nativeScaler, glyphCode, ptNumber);
 199         }
 200         return FontManager.getNullScaler().getGlyphPoint(
 201                    pScalerContext, glyphCode,  ptNumber);
 202     }
 203 
 204     synchronized long getUnitsPerEm() {
 205         return getUnitsPerEMNative(nativeScaler);
 206     }
 207 
 208     long createScalerContext(double[] matrix, boolean fontType,
 209             int aa, int fm, float boldness, float italic) {
 210         if (nativeScaler != 0L) {
 211             return createScalerContextNative(nativeScaler, matrix,
 212                       fontType, aa, fm, boldness, italic);
 213         }
 214         return NullFontScaler.getNullScalerContext();
 215     }
 216 
 217     //Note: native methods can throw RuntimeException if processing fails
 218     private native long initNativeScaler(Font2D font, int type,
 219             int indexInCollection, boolean supportsCJK, int filesize);
 220     private native StrikeMetrics getFontMetricsNative(Font2D font,
 221             long pScalerContext, long pScaler);
 222     private native float getGlyphAdvanceNative(Font2D font,
 223             long pScalerContext, long pScaler, int glyphCode);
 224     private native void getGlyphMetricsNative(Font2D font,
 225             long pScalerContext, long pScaler,
 226             int glyphCode, Point2D.Float metrics);
 227     private native long getGlyphImageNative(Font2D font,
 228             long pScalerContext, long pScaler, int glyphCode);
 229     private native Rectangle2D.Float getGlyphOutlineBoundsNative(Font2D font,
 230             long pScalerContext, long pScaler, int glyphCode);
 231     private native GeneralPath getGlyphOutlineNative(Font2D font,
 232             long pScalerContext, long pScaler,
 233             int glyphCode, float x, float y);
 234     private native GeneralPath getGlyphVectorOutlineNative(Font2D font,
 235             long pScalerContext, long pScaler,
 236             int[] glyphs, int numGlyphs, float x, float y);
 237     native Point2D.Float getGlyphPointNative(Font2D font,
 238             long pScalerContext, long pScaler, int glyphCode, int ptNumber);
 239 
 240     private native long getLayoutTableCacheNative(long pScaler);
 241 
 242     private native void disposeNativeScaler(long pScaler);
 243 
 244     private native int getGlyphCodeNative(long pScaler, char charCode);
 245     private native int getNumGlyphsNative(long pScaler);
 246     private native int getMissingGlyphCodeNative(long pScaler);
 247 
 248     private native long getUnitsPerEMNative(long pScaler);
 249 
 250     native long createScalerContextNative(long pScaler, double[] matrix,
 251             boolean fontType, int aa, int fm, float boldness, float italic);
 252 
 253     /* Freetype scaler context does not contain any pointers that
 254        has to be invalidated if native scaler is bad */
 255     void invalidateScalerContext(long pScalerContext) {}
 256 }