1 /* 2 * Copyright (c) 2003, 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.geom.AffineTransform; 29 import java.awt.geom.GeneralPath; 30 import java.awt.geom.Point2D; 31 import java.awt.Rectangle; 32 import java.awt.geom.Rectangle2D; 33 import java.awt.geom.NoninvertibleTransformException; 34 35 class NativeStrike extends PhysicalStrike { 36 37 NativeFont nativeFont; 38 int numGlyphs; 39 AffineTransform invertDevTx; 40 AffineTransform fontTx; 41 42 /* The following method prepares data used in obtaining FontMetrics. 43 * This is the one case in which we allow anything other than a 44 * simple scale to be used with a native font. We do this because in 45 * order to ensure that clients get the overall metrics they expect 46 * for a font whatever coordinate system (combination of font and 47 * device transform) they use. 48 * X11 fonts can only have a scale applied (remind : non-uniform?) 49 * We strip out everything else and if necessary obtain an inverse 50 * tx which we use to return metrics for the font in the transformed 51 * coordinate system of the font. ie we pass X11 a simple scale, and 52 * then apply the non-scale part of the font TX to that result. 53 */ getNativePointSize()54 private int getNativePointSize() { 55 /* Make a copy of the glyphTX in which we will store the 56 * font transform, inverting the devTx if necessary 57 */ 58 double[] mat = new double[4]; 59 desc.glyphTx.getMatrix(mat); 60 fontTx = new AffineTransform(mat); 61 62 /* Now work backwards to get the font transform */ 63 if (!desc.devTx.isIdentity() && 64 desc.devTx.getType() != AffineTransform.TYPE_TRANSLATION) { 65 try { 66 invertDevTx = desc.devTx.createInverse(); 67 fontTx.concatenate(invertDevTx); 68 } catch (NoninvertibleTransformException e) { 69 e.printStackTrace(); 70 } 71 } 72 73 /* At this point the fontTx may be a simple +ve scale, or it 74 * may be something more complex. 75 */ 76 Point2D.Float pt = new Point2D.Float(1f,1f); 77 fontTx.deltaTransform(pt, pt); 78 double ptSize = Math.abs(pt.y); 79 int ttype = fontTx.getType(); 80 if ((ttype & ~AffineTransform.TYPE_UNIFORM_SCALE) != 0 || 81 fontTx.getScaleY() <= 0) { 82 /* We need to create an inverse transform that doesn't 83 * include the point size (strictly the uniform scale) 84 */ 85 fontTx.scale(1/ptSize, 1/ptSize); 86 } else { 87 fontTx = null; // no need 88 } 89 return (int)ptSize; 90 } 91 NativeStrike(NativeFont nativeFont, FontStrikeDesc desc)92 NativeStrike(NativeFont nativeFont, FontStrikeDesc desc) { 93 super(nativeFont, desc); 94 this.nativeFont = nativeFont; 95 96 97 /* If this is a delegate for bitmaps, we expect to have 98 * been invoked only for a simple scale. If that's not 99 * true, just bail 100 */ 101 if (nativeFont.isBitmapDelegate) { 102 int ttype = desc.glyphTx.getType(); 103 if ((ttype & ~AffineTransform.TYPE_UNIFORM_SCALE) != 0 || 104 desc.glyphTx.getScaleX() <= 0) { 105 numGlyphs = 0; 106 return; 107 } 108 } 109 110 int ptSize = getNativePointSize(); 111 byte [] nameBytes = nativeFont.getPlatformNameBytes(ptSize); 112 double scale = Math.abs(desc.devTx.getScaleX()); 113 pScalerContext = createScalerContext(nameBytes, ptSize, scale); 114 if (pScalerContext == 0L) { 115 SunFontManager.getInstance().deRegisterBadFont(nativeFont); 116 pScalerContext = createNullScalerContext(); 117 numGlyphs = 0; 118 if (FontUtilities.isLogging()) { 119 FontUtilities.getLogger() 120 .severe("Could not create native strike " + 121 new String(nameBytes)); 122 } 123 return; 124 } 125 numGlyphs = nativeFont.getMapper().getNumGlyphs(); 126 this.disposer = new NativeStrikeDisposer(nativeFont, desc, 127 pScalerContext); 128 } 129 130 /* The asymmetry of the following methods is to help preserve 131 * performance with minimal textual changes to the calling code 132 * when moving initialisation of these arrays out of the constructor. 133 * This may be restructured later when there's more room for changes 134 */ usingIntGlyphImages()135 private boolean usingIntGlyphImages() { 136 if (intGlyphImages != null) { 137 return true; 138 } else if (longAddresses) { 139 return false; 140 } else { 141 /* We could obtain minGlyphIndex and index relative to that 142 * if we need to save space. 143 */ 144 int glyphLenArray = getMaxGlyph(pScalerContext); 145 146 /* This shouldn't be necessary - its a precaution */ 147 if (glyphLenArray < numGlyphs) { 148 glyphLenArray = numGlyphs; 149 } 150 intGlyphImages = new int[glyphLenArray]; 151 this.disposer.intGlyphImages = intGlyphImages; 152 return true; 153 } 154 } 155 getLongGlyphImages()156 private long[] getLongGlyphImages() { 157 if (longGlyphImages == null && longAddresses) { 158 159 /* We could obtain minGlyphIndex and index relative to that 160 * if we need to save space. 161 */ 162 int glyphLenArray = getMaxGlyph(pScalerContext); 163 164 /* This shouldn't be necessary - its a precaution */ 165 if (glyphLenArray < numGlyphs) { 166 glyphLenArray = numGlyphs; 167 } 168 longGlyphImages = new long[glyphLenArray]; 169 this.disposer.longGlyphImages = longGlyphImages; 170 } 171 return longGlyphImages; 172 } 173 NativeStrike(NativeFont nativeFont, FontStrikeDesc desc, boolean nocache)174 NativeStrike(NativeFont nativeFont, FontStrikeDesc desc, 175 boolean nocache) { 176 super(nativeFont, desc); 177 this.nativeFont = nativeFont; 178 179 int ptSize = (int)desc.glyphTx.getScaleY(); 180 double scale = desc.devTx.getScaleX(); // uniform scale 181 byte [] nameBytes = nativeFont.getPlatformNameBytes(ptSize); 182 pScalerContext = createScalerContext(nameBytes, ptSize, scale); 183 184 int numGlyphs = nativeFont.getMapper().getNumGlyphs(); 185 } 186 187 /* We want the native font to be responsible for reporting the 188 * font metrics, even if it often delegates to another font. 189 * The code here isn't yet implementing exactly that. If the glyph 190 * transform was something native couldn't handle, there's no native 191 * context from which to obtain metrics. Need to revise this to obtain 192 * the metrics and transform them. But currently in such a case it 193 * gets the metrics from a different font - its glyph delegate font. 194 */ getFontMetrics()195 StrikeMetrics getFontMetrics() { 196 if (strikeMetrics == null) { 197 if (pScalerContext != 0) { 198 strikeMetrics = nativeFont.getFontMetrics(pScalerContext); 199 } 200 if (strikeMetrics != null && fontTx != null) { 201 strikeMetrics.convertToUserSpace(fontTx); 202 } 203 } 204 return strikeMetrics; 205 } 206 createScalerContext(byte[] nameBytes, int ptSize, double scale)207 private native long createScalerContext(byte[] nameBytes, 208 int ptSize, double scale); 209 getMaxGlyph(long pScalerContext)210 private native int getMaxGlyph(long pScalerContext); 211 createNullScalerContext()212 private native long createNullScalerContext(); 213 getGlyphImagePtrs(int[] glyphCodes, long[] images,int len)214 void getGlyphImagePtrs(int[] glyphCodes, long[] images,int len) { 215 for (int i=0; i<len; i++) { 216 images[i] = getGlyphImagePtr(glyphCodes[i]); 217 } 218 } 219 getGlyphImagePtr(int glyphCode)220 long getGlyphImagePtr(int glyphCode) { 221 long glyphPtr; 222 223 if (usingIntGlyphImages()) { 224 if ((glyphPtr = intGlyphImages[glyphCode] & INTMASK) != 0L) { 225 return glyphPtr; 226 } else { 227 glyphPtr = nativeFont.getGlyphImage(pScalerContext,glyphCode); 228 /* Synchronize in case some other thread has updated this 229 * cache entry already - unlikely but possible. 230 */ 231 synchronized (this) { 232 if (intGlyphImages[glyphCode] == 0) { 233 intGlyphImages[glyphCode] = (int)glyphPtr; 234 return glyphPtr; 235 } else { 236 StrikeCache.freeIntPointer((int)glyphPtr); 237 return intGlyphImages[glyphCode] & INTMASK; 238 } 239 } 240 } 241 } 242 /* must be using long (8 byte) addresses */ 243 else if ((glyphPtr = getLongGlyphImages()[glyphCode]) != 0L) { 244 return glyphPtr; 245 } else { 246 glyphPtr = nativeFont.getGlyphImage(pScalerContext, glyphCode); 247 248 synchronized (this) { 249 if (longGlyphImages[glyphCode] == 0L) { 250 longGlyphImages[glyphCode] = glyphPtr; 251 return glyphPtr; 252 } else { 253 StrikeCache.freeLongPointer(glyphPtr); 254 return longGlyphImages[glyphCode]; 255 } 256 } 257 } 258 } 259 260 /* This is used when a FileFont uses the native names to create a 261 * delegate NativeFont/Strike to get images from native. This is used 262 * because Solaris TrueType fonts have external PCF bitmaps rather than 263 * embedded bitmaps. This is really only important for CJK fonts as 264 * for most scripts the external X11 bitmaps aren't much better - if 265 * at all - than the results from hinting the outlines. 266 */ getGlyphImagePtrNoCache(int glyphCode)267 long getGlyphImagePtrNoCache(int glyphCode) { 268 return nativeFont.getGlyphImageNoDefault(pScalerContext, glyphCode); 269 } 270 getGlyphImageBounds(int glyphcode, Point2D.Float pt, Rectangle result)271 void getGlyphImageBounds(int glyphcode, Point2D.Float pt, 272 Rectangle result) { 273 } 274 getGlyphMetrics(int glyphCode)275 Point2D.Float getGlyphMetrics(int glyphCode) { 276 Point2D.Float pt = new Point2D.Float(getGlyphAdvance(glyphCode), 0f); 277 return pt; 278 } 279 getGlyphAdvance(int glyphCode)280 float getGlyphAdvance(int glyphCode) { 281 return nativeFont.getGlyphAdvance(pScalerContext, glyphCode); 282 } 283 getGlyphOutlineBounds(int glyphCode)284 Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) { 285 return nativeFont.getGlyphOutlineBounds(pScalerContext, glyphCode); 286 } 287 getGlyphOutline(int glyphCode, float x, float y)288 GeneralPath getGlyphOutline(int glyphCode, float x, float y) { 289 return new GeneralPath(); 290 } 291 getGlyphVectorOutline(int[] glyphs, float x, float y)292 GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) { 293 return new GeneralPath(); 294 } 295 296 } 297