1 /*
   2  * Copyright (c) 2011, 2012, 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.Font;
  29 import java.awt.font.FontRenderContext;
  30 import java.awt.geom.AffineTransform;
  31 import java.awt.geom.GeneralPath;;
  32 import java.awt.geom.Point2D;
  33 import java.awt.geom.Rectangle2D;
  34 
  35 // Right now this class is final to avoid a problem with native code.
  36 // For some reason the JNI IsInstanceOf was not working correctly
  37 // so we are checking the class specifically. If we subclass this
  38 // we need to modify the native code in CFontWrapper.m
  39 public final class CFont extends PhysicalFont {
  40 
  41     /* CFontStrike doesn't call these methods so they are unimplemented.
  42      * They are here to meet the requirements of PhysicalFont, needed
  43      * because a CFont can sometimes be returned where a PhysicalFont
  44      * is expected.
  45      */
  46     StrikeMetrics getFontMetrics(long pScalerContext) {
  47        throw new InternalError("Not implemented");
  48     }
  49 
  50     float getGlyphAdvance(long pScalerContext, int glyphCode) {
  51        throw new InternalError("Not implemented");
  52     }
  53 
  54     void getGlyphMetrics(long pScalerContext, int glyphCode,
  55                                   Point2D.Float metrics) {
  56        throw new InternalError("Not implemented");
  57     }
  58 
  59     long getGlyphImage(long pScalerContext, int glyphCode) {
  60        throw new InternalError("Not implemented");
  61     }
  62 
  63     Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext,
  64                                                      int glyphCode) {
  65        throw new InternalError("Not implemented");
  66     }
  67 
  68     GeneralPath getGlyphOutline(long pScalerContext, int glyphCode,
  69                                          float x, float y) {
  70        throw new InternalError("Not implemented");
  71     }
  72 
  73     GeneralPath getGlyphVectorOutline(long pScalerContext,
  74                                                int[] glyphs, int numGlyphs,
  75                                                float x, float y) {
  76        throw new InternalError("Not implemented");
  77     }
  78 
  79     private static native long createNativeFont(final String nativeFontName,
  80                                                 final int style);
  81     private static native void disposeNativeFont(final long nativeFontPtr);
  82 
  83     private boolean isFakeItalic;
  84     private String nativeFontName;
  85     private long nativeFontPtr;
  86 
  87     private native float getWidthNative(final long nativeFontPtr);
  88     private native float getWeightNative(final long nativeFontPtr);
  89 
  90     private int fontWidth = -1;
  91     private int fontWeight = -1;
  92 
  93     @Override
  94     public int getWidth() {
  95         if (fontWidth == -1) {
  96             // Apple use a range of -1 -> +1, where 0.0 is normal
  97             // OpenType uses a % range from 50% -> 200% where 100% is normal
  98             // and maps these onto the integer values 1->9.
  99             // Since that is what Font2D.getWidth() expects, remap to that.
 100             float fw = getWidthNative(getNativeFontPtr());
 101             if (fw == 0.0) { // short cut the common case
 102                 fontWidth = Font2D.FWIDTH_NORMAL;
 103                 return fontWidth;
 104             }
 105             fw += 1.0; fw *= 100.0;
 106             if (fw <= 50.0) {
 107                 fontWidth = 1;
 108             } else if (fw <= 62.5) {
 109                 fontWidth = 2;
 110             } else if (fw <= 75.0) {
 111                 fontWidth = 3;
 112             } else if (fw <= 87.5) {
 113                 fontWidth = 4;
 114             } else if (fw <= 100.0) {
 115                 fontWidth = 5;
 116             } else if (fw <= 112.5) {
 117                 fontWidth = 6;
 118             } else if (fw <= 125.0) {
 119                 fontWidth = 7;
 120             } else if (fw <= 150.0) {
 121                 fontWidth = 8;
 122             } else {
 123                 fontWidth = 9;
 124             }
 125         }
 126         return fontWidth;
 127    }
 128 
 129     @Override
 130     public int getWeight() {
 131         if (fontWeight == -1) {
 132             // Apple use a range of -1 -> +1, where 0 is medium/regular
 133             // Map this on to the OpenType range of 100->900 where
 134             // 500 is medium/regular.
 135             // We'll actually map to 0->1000 but that's close enough.
 136             float fw = getWeightNative(getNativeFontPtr());
 137             if (fw == 0) {
 138                return Font2D.FWEIGHT_NORMAL;
 139             }
 140             fw += 1.0; fw *= 500;
 141             fontWeight = (int)fw;
 142           }
 143           return fontWeight;
 144     }
 145     
 146     // this constructor is called from CFontWrapper.m
 147     public CFont(String name) {
 148         this(name, name);
 149     }
 150 
 151     public CFont(String name, String inFamilyName) {
 152         handle = new Font2DHandle(this);
 153         fullName = name;
 154         familyName = inFamilyName;
 155         nativeFontName = fullName;
 156         setStyle();
 157     }
 158 
 159     /* Called from CFontManager too */
 160     public CFont(CFont other, String logicalFamilyName) {
 161         handle = new Font2DHandle(this);
 162         fullName = logicalFamilyName;
 163         familyName = logicalFamilyName;
 164         nativeFontName = other.nativeFontName;
 165         style = other.style;
 166         isFakeItalic = other.isFakeItalic;
 167     }
 168 
 169     public CFont createItalicVariant() {
 170         CFont font = new CFont(this, familyName);
 171         font.nativeFontName = fullName;
 172         font.fullName =
 173             fullName + (style == Font.BOLD ? "" : "-") + "Italic-Derived";
 174         font.style |= Font.ITALIC;
 175         font.isFakeItalic = true;
 176         return font;
 177     }
 178 
 179     protected synchronized long getNativeFontPtr() {
 180         if (nativeFontPtr == 0L) {
 181             nativeFontPtr = createNativeFont(nativeFontName, style);
 182 }
 183         return nativeFontPtr;
 184     }
 185 
 186     protected synchronized void finalize() {
 187         if (nativeFontPtr != 0) {
 188             disposeNativeFont(nativeFontPtr);
 189         }
 190         nativeFontPtr = 0;
 191     }
 192 
 193     protected CharToGlyphMapper getMapper() {
 194         if (mapper == null) {
 195             mapper = new CCharToGlyphMapper(this);
 196         }
 197         return mapper;
 198     }
 199 
 200     protected FontStrike createStrike(FontStrikeDesc desc) {
 201         if (isFakeItalic) {
 202             desc = new FontStrikeDesc(desc);
 203             desc.glyphTx.concatenate(AffineTransform.getShearInstance(-0.2, 0));
 204         }
 205         return new CStrike(this, desc);
 206     }
 207 
 208     // <rdar://problem/5321707> sun.font.Font2D caches the last used strike,
 209     // but does not check if the properties of the strike match the properties
 210     // of the incoming java.awt.Font object (size, style, etc).
 211     // Simple answer: don't cache.
 212     private static FontRenderContext DEFAULT_FRC =
 213         new FontRenderContext(null, false, false);
 214     public FontStrike getStrike(final Font font) {
 215         return getStrike(font, DEFAULT_FRC);
 216     }
 217 
 218     public String toString() {
 219         return "CFont { fullName: " + fullName +
 220             ",  familyName: " + familyName + ", style: " + style +
 221             " } aka: " + super.toString();
 222     }
 223 }