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