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 */
  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 }