1 /* 2 * Copyright (c) 2003, 2020, 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.logSevere("Could not create native strike " + 120 new String(nameBytes)); 121 } 122 return; 123 } 124 numGlyphs = nativeFont.getMapper().getNumGlyphs(); 125 this.disposer = new NativeStrikeDisposer(nativeFont, desc, 126 pScalerContext); 127 } 128 129 /* The asymmetry of the following methods is to help preserve 130 * performance with minimal textual changes to the calling code 131 * when moving initialisation of these arrays out of the constructor. 132 * This may be restructured later when there's more room for changes 133 */ usingIntGlyphImages()134 private boolean usingIntGlyphImages() { 135 if (intGlyphImages != null) { 136 return true; 137 } else if (longAddresses) { 138 return false; 139 } else { 140 /* We could obtain minGlyphIndex and index relative to that 141 * if we need to save space. 142 */ 143 int glyphLenArray = getMaxGlyph(pScalerContext); 144 145 /* This shouldn't be necessary - its a precaution */ 146 if (glyphLenArray < numGlyphs) { 147 glyphLenArray = numGlyphs; 148 } 149 intGlyphImages = new int[glyphLenArray]; 150 this.disposer.intGlyphImages = intGlyphImages; 151 return true; 152 } 153 } 154 getLongGlyphImages()155 private long[] getLongGlyphImages() { 156 if (longGlyphImages == null && longAddresses) { 157 158 /* We could obtain minGlyphIndex and index relative to that 159 * if we need to save space. 160 */ 161 int glyphLenArray = getMaxGlyph(pScalerContext); 162 163 /* This shouldn't be necessary - its a precaution */ 164 if (glyphLenArray < numGlyphs) { 165 glyphLenArray = numGlyphs; 166 } 167 longGlyphImages = new long[glyphLenArray]; 168 this.disposer.longGlyphImages = longGlyphImages; 169 } 170 return longGlyphImages; 171 } 172 NativeStrike(NativeFont nativeFont, FontStrikeDesc desc, boolean nocache)173 NativeStrike(NativeFont nativeFont, FontStrikeDesc desc, 174 boolean nocache) { 175 super(nativeFont, desc); 176 this.nativeFont = nativeFont; 177 178 int ptSize = (int)desc.glyphTx.getScaleY(); 179 double scale = desc.devTx.getScaleX(); // uniform scale 180 byte [] nameBytes = nativeFont.getPlatformNameBytes(ptSize); 181 pScalerContext = createScalerContext(nameBytes, ptSize, scale); 182 183 int numGlyphs = nativeFont.getMapper().getNumGlyphs(); 184 } 185 186 /* We want the native font to be responsible for reporting the 187 * font metrics, even if it often delegates to another font. 188 * The code here isn't yet implementing exactly that. If the glyph 189 * transform was something native couldn't handle, there's no native 190 * context from which to obtain metrics. Need to revise this to obtain 191 * the metrics and transform them. But currently in such a case it 192 * gets the metrics from a different font - its glyph delegate font. 193 */ getFontMetrics()194 StrikeMetrics getFontMetrics() { 195 if (strikeMetrics == null) { 196 if (pScalerContext != 0) { 197 strikeMetrics = nativeFont.getFontMetrics(pScalerContext); 198 } 199 if (strikeMetrics != null && fontTx != null) { 200 strikeMetrics.convertToUserSpace(fontTx); 201 } 202 } 203 return strikeMetrics; 204 } 205 createScalerContext(byte[] nameBytes, int ptSize, double scale)206 private native long createScalerContext(byte[] nameBytes, 207 int ptSize, double scale); 208 getMaxGlyph(long pScalerContext)209 private native int getMaxGlyph(long pScalerContext); 210 createNullScalerContext()211 private native long createNullScalerContext(); 212 getGlyphImagePtrs(int[] glyphCodes, long[] images,int len)213 void getGlyphImagePtrs(int[] glyphCodes, long[] images,int len) { 214 for (int i=0; i<len; i++) { 215 images[i] = getGlyphImagePtr(glyphCodes[i]); 216 } 217 } 218 getGlyphImagePtr(int glyphCode)219 long getGlyphImagePtr(int glyphCode) { 220 long glyphPtr; 221 222 if (usingIntGlyphImages()) { 223 if ((glyphPtr = intGlyphImages[glyphCode] & INTMASK) != 0L) { 224 return glyphPtr; 225 } else { 226 glyphPtr = nativeFont.getGlyphImage(pScalerContext,glyphCode); 227 /* Synchronize in case some other thread has updated this 228 * cache entry already - unlikely but possible. 229 */ 230 synchronized (this) { 231 if (intGlyphImages[glyphCode] == 0) { 232 intGlyphImages[glyphCode] = (int)glyphPtr; 233 return glyphPtr; 234 } else { 235 StrikeCache.freeIntPointer((int)glyphPtr); 236 return intGlyphImages[glyphCode] & INTMASK; 237 } 238 } 239 } 240 } 241 /* must be using long (8 byte) addresses */ 242 else if ((glyphPtr = getLongGlyphImages()[glyphCode]) != 0L) { 243 return glyphPtr; 244 } else { 245 glyphPtr = nativeFont.getGlyphImage(pScalerContext, glyphCode); 246 247 synchronized (this) { 248 if (longGlyphImages[glyphCode] == 0L) { 249 longGlyphImages[glyphCode] = glyphPtr; 250 return glyphPtr; 251 } else { 252 StrikeCache.freeLongPointer(glyphPtr); 253 return longGlyphImages[glyphCode]; 254 } 255 } 256 } 257 } 258 259 /* This is used when a FileFont uses the native names to create a 260 * delegate NativeFont/Strike to get images from native. This is used 261 * because Solaris TrueType fonts have external PCF bitmaps rather than 262 * embedded bitmaps. This is really only important for CJK fonts as 263 * for most scripts the external X11 bitmaps aren't much better - if 264 * at all - than the results from hinting the outlines. 265 */ getGlyphImagePtrNoCache(int glyphCode)266 long getGlyphImagePtrNoCache(int glyphCode) { 267 return nativeFont.getGlyphImageNoDefault(pScalerContext, glyphCode); 268 } 269 getGlyphImageBounds(int glyphcode, Point2D.Float pt, Rectangle result)270 void getGlyphImageBounds(int glyphcode, Point2D.Float pt, 271 Rectangle result) { 272 } 273 getGlyphMetrics(int glyphCode)274 Point2D.Float getGlyphMetrics(int glyphCode) { 275 Point2D.Float pt = new Point2D.Float(getGlyphAdvance(glyphCode), 0f); 276 return pt; 277 } 278 getGlyphAdvance(int glyphCode)279 float getGlyphAdvance(int glyphCode) { 280 return nativeFont.getGlyphAdvance(pScalerContext, glyphCode); 281 } 282 getGlyphOutlineBounds(int glyphCode)283 Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) { 284 return nativeFont.getGlyphOutlineBounds(pScalerContext, glyphCode); 285 } 286 getGlyphOutline(int glyphCode, float x, float y)287 GeneralPath getGlyphOutline(int glyphCode, float x, float y) { 288 return new GeneralPath(); 289 } 290 getGlyphVectorOutline(int[] glyphs, float x, float y)291 GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) { 292 return new GeneralPath(); 293 } 294 295 } 296