1 /* 2 * Copyright (c) 2011, 2017, 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 */ getFontMetrics(long pScalerContext)47 StrikeMetrics getFontMetrics(long pScalerContext) { 48 throw new InternalError("Not implemented"); 49 } 50 getGlyphAdvance(long pScalerContext, int glyphCode)51 float getGlyphAdvance(long pScalerContext, int glyphCode) { 52 throw new InternalError("Not implemented"); 53 } 54 getGlyphMetrics(long pScalerContext, int glyphCode, Point2D.Float metrics)55 void getGlyphMetrics(long pScalerContext, int glyphCode, 56 Point2D.Float metrics) { 57 throw new InternalError("Not implemented"); 58 } 59 getGlyphImage(long pScalerContext, int glyphCode)60 long getGlyphImage(long pScalerContext, int glyphCode) { 61 throw new InternalError("Not implemented"); 62 } 63 getGlyphOutlineBounds(long pScalerContext, int glyphCode)64 Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext, 65 int glyphCode) { 66 throw new InternalError("Not implemented"); 67 } 68 getGlyphOutline(long pScalerContext, int glyphCode, float x, float y)69 GeneralPath getGlyphOutline(long pScalerContext, int glyphCode, 70 float x, float y) { 71 throw new InternalError("Not implemented"); 72 } 73 getGlyphVectorOutline(long pScalerContext, int[] glyphs, int numGlyphs, float x, float y)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 getLayoutTableCache()81 protected long getLayoutTableCache() { 82 return getLayoutTableCacheNative(getNativeFontPtr()); 83 } 84 85 @Override getTableBytes(int tag)86 protected byte[] getTableBytes(int tag) { 87 return getTableBytesNative(getNativeFontPtr(), tag); 88 } 89 getLayoutTableCacheNative(long nativeFontPtr)90 private native synchronized long getLayoutTableCacheNative(long nativeFontPtr); 91 getTableBytesNative(long nativeFontPtr, int tag)92 private native byte[] getTableBytesNative(long nativeFontPtr, int tag); 93 createNativeFont(final String nativeFontName, final int style)94 private static native long createNativeFont(final String nativeFontName, 95 final int style); disposeNativeFont(final long nativeFontPtr)96 private static native void disposeNativeFont(final long nativeFontPtr); 97 98 private boolean isFakeItalic; 99 private String nativeFontName; 100 private long nativeFontPtr; 101 getWidthNative(final long nativeFontPtr)102 private native float getWidthNative(final long nativeFontPtr); getWeightNative(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 getWidth()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 getWeight()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 CFont(String name)162 public CFont(String name) { 163 this(name, name); 164 } 165 CFont(String name, String inFamilyName)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 */ CFont(CFont other, String logicalFamilyName)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 createItalicVariant()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 getNativeFontPtr()194 protected synchronized long getNativeFontPtr() { 195 if (nativeFontPtr == 0L) { 196 nativeFontPtr = createNativeFont(nativeFontName, style); 197 } 198 return nativeFontPtr; 199 } 200 getCascadeList(long nativeFontPtr, ArrayList<String> listOfString)201 static native void getCascadeList(long nativeFontPtr, ArrayList<String> listOfString); 202 createCompositeFont()203 private CompositeFont createCompositeFont() { 204 ArrayList<String> listOfString = new ArrayList<String>(); 205 getCascadeList(nativeFontPtr, listOfString); 206 207 // add JRE "Lucida Sans Regular" to the cascade list to enable fallback 208 // to happen to this JRE font in case the intended glyph is missing in 209 // fonts provided in the CoreText provided cascaded list 210 listOfString.add("Lucida Sans Regular"); 211 FontManager fm = FontManagerFactory.getInstance(); 212 int numFonts = 1 + listOfString.size(); 213 PhysicalFont[] fonts = new PhysicalFont[numFonts]; 214 fonts[0] = this; 215 int idx = 1; 216 for (String s : listOfString) { 217 if (s.equals(".AppleSymbolsFB")) { 218 // Don't know why we get the weird name above .. replace. 219 s = "AppleSymbols"; 220 } 221 Font2D f2d = fm.findFont2D(s, Font.PLAIN, FontManager.NO_FALLBACK); 222 if (f2d == null || f2d == this) { 223 continue; 224 } 225 fonts[idx++] = (PhysicalFont)f2d; 226 } 227 if (idx < fonts.length) { 228 PhysicalFont[] orig = fonts; 229 fonts = new PhysicalFont[idx]; 230 System.arraycopy(orig, 0, fonts, 0, idx); 231 } 232 CompositeFont compFont = new CompositeFont(fonts); 233 compFont.mapper = new CCompositeGlyphMapper(compFont); 234 return compFont; 235 } 236 237 private CompositeFont compFont; 238 getCompositeFont2D()239 public CompositeFont getCompositeFont2D() { 240 if (compFont == null) { 241 compFont = createCompositeFont(); 242 } 243 return compFont; 244 } 245 finalize()246 protected synchronized void finalize() { 247 if (nativeFontPtr != 0) { 248 disposeNativeFont(nativeFontPtr); 249 } 250 nativeFontPtr = 0; 251 } 252 getMapper()253 protected CharToGlyphMapper getMapper() { 254 if (mapper == null) { 255 mapper = new CCharToGlyphMapper(this); 256 } 257 return mapper; 258 } 259 createStrike(FontStrikeDesc desc)260 protected FontStrike createStrike(FontStrikeDesc desc) { 261 if (isFakeItalic) { 262 desc = new FontStrikeDesc(desc); 263 desc.glyphTx.concatenate(AffineTransform.getShearInstance(-0.2, 0)); 264 } 265 return new CStrike(this, desc); 266 } 267 268 // <rdar://problem/5321707> sun.font.Font2D caches the last used strike, 269 // but does not check if the properties of the strike match the properties 270 // of the incoming java.awt.Font object (size, style, etc). 271 // Simple answer: don't cache. 272 private static FontRenderContext DEFAULT_FRC = 273 new FontRenderContext(null, false, false); getStrike(final Font font)274 public FontStrike getStrike(final Font font) { 275 return getStrike(font, DEFAULT_FRC); 276 } 277 toString()278 public String toString() { 279 return "CFont { fullName: " + fullName + 280 ", familyName: " + familyName + ", style: " + style + 281 " } aka: " + super.toString(); 282 } 283 } 284